目录

 

1、项目创建

1.1 初始化的 pom.xml文件

1.2 应用初始化设置

2、验证码生成前的准备

2.1 分析

2.2 整合 redis

2.3 验证码生成的工具类

2.4 定义一个统一返回给前台数据的类对象

2.5 定义返回状态码

2.6 字符串的工具类

2.7 UUID生成工具类

2.8 通用常量类

2.9 base64 编码工具

3、生成验证码

4、测试

5、总结


1、项目创建

1.1 初始化的 pom.xml文件

主要内容:

    <!-- 项目坐标 --><groupId>com.ruoyi</groupId><artifactId>ruoyi</artifactId><version>0.0.1-SNAPSHOT</version><!-- 父工程 --><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.1.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><!-- 依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- SpringBoot Web容器 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>

1.2 应用初始化设置

设置 端口号 和 应用访问的根路径

server:# 配置端口port: 8888servlet:# 应用访问路径context-path: /ruoyi

2、验证码生成前的准备

2.1 分析

浏览器发送:http://127.0.0.1:8888/ruoyi/captcha/captchaImage

服务器:

①、生成4位随机数

②、生成UUID

③、将验证码存入到 redis 中,key 为 UUID, 值为生成的4个随机数

④、生成验证码图片

⑤、将 验证码图片 和 UUID 放入返回结果中

2.2 整合 redis

2.2.1 引入 redis 相关依赖

        <!-- redis 缓存操作 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><!-- pool 对象池 --><dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId></dependency><!-- 阿里JSON解析器 --><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>${fastjson.version}</version></dependency>

2.2.2 配置 redis 

application.yml 文件新增配置

spring:# redis 配置redis:# 地址host: 114.67.69.222# 端口,默认为6379port: 6379# 密码password:    #填写自己的密码# 连接超时时间timeout: 10slettuce:pool:# 连接池中的最小空闲连接min-idle: 0# 连接池中的最大空闲连接max-idle: 8# 连接池的最大数据库连接数max-active: 8# #连接池最大阻塞等待时间(使用负值表示没有限制)max-wait: -1ms

新增redis的配置类

package com.ruoyi.framework.config;/*** redis配置** @author ruoyi*/
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport
{@Bean@SuppressWarnings(value = { "unchecked", "rawtypes" })public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory){RedisTemplate<Object, Object> template = new RedisTemplate<>();template.setConnectionFactory(connectionFactory);FastJson2JsonRedisSerializer serializer = new FastJson2JsonRedisSerializer(Object.class);ObjectMapper mapper = new ObjectMapper();mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);serializer.setObjectMapper(mapper);template.setValueSerializer(serializer);// 使用StringRedisSerializer来序列化和反序列化redis的key值template.setKeySerializer(new StringRedisSerializer());template.afterPropertiesSet();return template;}
}

redis 配置类中用到了 fastJson 序列号, 下面是序列号类代码

package com.ruoyi.framework.config;/*** Redis使用FastJson序列化** @author ruoyi*/
public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T> {@SuppressWarnings("unused")private ObjectMapper objectMapper = new ObjectMapper();public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");private Class<T> clazz;static {ParserConfig.getGlobalInstance().setAutoTypeSupport(true);}public FastJson2JsonRedisSerializer(Class<T> clazz) {super();this.clazz = clazz;}public byte[] serialize(T t) throws SerializationException {if (t == null) {return new byte[0];}return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);}public T deserialize(byte[] bytes) throws SerializationException {if (bytes == null || bytes.length <= 0) {return null;}String str = new String(bytes, DEFAULT_CHARSET);return JSON.parseObject(str, clazz);}public void setObjectMapper(ObjectMapper objectMapper) {Assert.notNull(objectMapper, "'objectMapper' must not be null");this.objectMapper = objectMapper;}protected JavaType getJavaType(Class<?> clazz) {return TypeFactory.defaultInstance().constructType(clazz);}
}

2.2.3 redis工具类

封装redis 的增删改查操作

package com.ruoyi.framework.redis;/*** spring redis 工具类** @author ruoyi**/
@SuppressWarnings(value = {"unchecked", "rawtypes"})
@Component
public class RedisCache {@Autowiredpublic RedisTemplate redisTemplate;/*** 缓存基本的对象,Integer、String、实体类等** @param key   缓存的键值* @param value 缓存的值* @return 缓存的对象*/public <T> ValueOperations<String, T> setCacheObject(String key, T value) {ValueOperations<String, T> operation = redisTemplate.opsForValue();operation.set(key, value);return operation;}/*** 缓存基本的对象,Integer、String、实体类等** @param key      缓存的键值* @param value    缓存的值* @param timeout  时间* @param timeUnit 时间颗粒度* @return 缓存的对象*/public <T> ValueOperations<String, T> setCacheObject(String key, T value, Integer timeout, TimeUnit timeUnit) {ValueOperations<String, T> operation = redisTemplate.opsForValue();operation.set(key, value, timeout, timeUnit);return operation;}/*** 获得缓存的基本对象。** @param key 缓存键值* @return 缓存键值对应的数据*/public <T> T getCacheObject(String key) {ValueOperations<String, T> operation = redisTemplate.opsForValue();return operation.get(key);}/*** 删除单个对象** @param key*/public void deleteObject(String key) {redisTemplate.delete(key);}/*** 删除集合对象** @param collection*/public void deleteObject(Collection collection) {redisTemplate.delete(collection);}/*** 缓存List数据** @param key      缓存的键值* @param dataList 待缓存的List数据* @return 缓存的对象*/public <T> ListOperations<String, T> setCacheList(String key, List<T> dataList) {ListOperations listOperation = redisTemplate.opsForList();if (null != dataList) {int size = dataList.size();for (int i = 0; i < size; i++) {listOperation.leftPush(key, dataList.get(i));}}return listOperation;}/*** 获得缓存的list对象** @param key 缓存的键值* @return 缓存键值对应的数据*/public <T> List<T> getCacheList(String key) {List<T> dataList = new ArrayList<T>();ListOperations<String, T> listOperation = redisTemplate.opsForList();Long size = listOperation.size(key);for (int i = 0; i < size; i++) {dataList.add(listOperation.index(key, i));}return dataList;}/*** 缓存Set** @param key     缓存键值* @param dataSet 缓存的数据* @return 缓存数据的对象*/public <T> BoundSetOperations<String, T> setCacheSet(String key, Set<T> dataSet) {BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key);Iterator<T> it = dataSet.iterator();while (it.hasNext()) {setOperation.add(it.next());}return setOperation;}/*** 获得缓存的set** @param key* @return*/public <T> Set<T> getCacheSet(String key) {Set<T> dataSet = new HashSet<T>();BoundSetOperations<String, T> operation = redisTemplate.boundSetOps(key);dataSet = operation.members();return dataSet;}/*** 缓存Map** @param key* @param dataMap* @return*/public <T> HashOperations<String, String, T> setCacheMap(String key, Map<String, T> dataMap) {HashOperations hashOperations = redisTemplate.opsForHash();if (null != dataMap) {for (Map.Entry<String, T> entry : dataMap.entrySet()) {hashOperations.put(key, entry.getKey(), entry.getValue());}}return hashOperations;}/*** 获得缓存的Map** @param key* @return*/public <T> Map<String, T> getCacheMap(String key) {Map<String, T> map = redisTemplate.opsForHash().entries(key);return map;}/*** 获得缓存的基本对象列表** @param pattern 字符串前缀* @return 对象列表*/public Collection<String> keys(String pattern) {return redisTemplate.keys(pattern);}
}

2.3 验证码生成的工具类

该类用于生成4位随机字符串 和 验证码图片输出

package com.ruoyi.common.utils;/*** 验证码工具类** @author ruoyi*/
public class VerifyCodeUtils {// 使用到Algerian字体,系统里没有的话需要安装字体,字体只显示大写,去掉了1,0,i,o几个容易混淆的字符public static final String VERIFY_CODES = "123456789ABCDEFGHJKLMNPQRSTUVWXYZ";private static Random random = new SecureRandom();/*** 使用系统默认字符源生成验证码** @param verifySize 验证码长度* @return*/public static String generateVerifyCode(int verifySize) {return generateVerifyCode(verifySize, VERIFY_CODES);}/*** 使用指定源生成验证码** @param verifySize 验证码长度* @param sources    验证码字符源* @return*/public static String generateVerifyCode(int verifySize, String sources) {if (sources == null || sources.length() == 0) {sources = VERIFY_CODES;}int codesLen = sources.length();Random rand = new Random(System.currentTimeMillis());StringBuilder verifyCode = new StringBuilder(verifySize);for (int i = 0; i < verifySize; i++) {verifyCode.append(sources.charAt(rand.nextInt(codesLen - 1)));}return verifyCode.toString();}/*** 输出指定验证码图片流** @param w* @param h* @param os* @param code* @throws IOException*/public static void outputImage(int w, int h, OutputStream os, String code) throws IOException {int verifySize = code.length();BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);Random rand = new Random();Graphics2D g2 = image.createGraphics();g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);Color[] colors = new Color[5];Color[] colorSpaces = new Color[]{Color.WHITE, Color.CYAN, Color.GRAY, Color.LIGHT_GRAY, Color.MAGENTA,Color.ORANGE, Color.PINK, Color.YELLOW};float[] fractions = new float[colors.length];for (int i = 0; i < colors.length; i++) {colors[i] = colorSpaces[rand.nextInt(colorSpaces.length)];fractions[i] = rand.nextFloat();}Arrays.sort(fractions);g2.setColor(Color.GRAY);// 设置边框色g2.fillRect(0, 0, w, h);Color c = getRandColor(200, 250);g2.setColor(c);// 设置背景色g2.fillRect(0, 2, w, h - 4);// 绘制干扰线Random random = new Random();g2.setColor(getRandColor(160, 200));// 设置线条的颜色for (int i = 0; i < 20; i++) {int x = random.nextInt(w - 1);int y = random.nextInt(h - 1);int xl = random.nextInt(6) + 1;int yl = random.nextInt(12) + 1;g2.drawLine(x, y, x + xl + 40, y + yl + 20);}// 添加噪点float yawpRate = 0.05f;// 噪声率int area = (int) (yawpRate * w * h);for (int i = 0; i < area; i++) {int x = random.nextInt(w);int y = random.nextInt(h);int rgb = getRandomIntColor();image.setRGB(x, y, rgb);}shear(g2, w, h, c);// 使图片扭曲g2.setColor(getRandColor(100, 160));int fontSize = h - 4;Font font = new Font("Algerian", Font.ITALIC, fontSize);g2.setFont(font);char[] chars = code.toCharArray();for (int i = 0; i < verifySize; i++) {AffineTransform affine = new AffineTransform();affine.setToRotation(Math.PI / 4 * rand.nextDouble() * (rand.nextBoolean() ? 1 : -1),(w / verifySize) * i + fontSize / 2, h / 2);g2.setTransform(affine);g2.drawChars(chars, i, 1, ((w - 10) / verifySize) * i + 5, h / 2 + fontSize / 2 - 10);}g2.dispose();ImageIO.write(image, "jpg", os);}private static Color getRandColor(int fc, int bc) {if (fc > 255)fc = 255;if (bc > 255)bc = 255;int r = fc + random.nextInt(bc - fc);int g = fc + random.nextInt(bc - fc);int b = fc + random.nextInt(bc - fc);return new Color(r, g, b);}private static int getRandomIntColor() {int[] rgb = getRandomRgb();int color = 0;for (int c : rgb) {color = color << 8;color = color | c;}return color;}private static int[] getRandomRgb() {int[] rgb = new int[3];for (int i = 0; i < 3; i++) {rgb[i] = random.nextInt(255);}return rgb;}private static void shear(Graphics g, int w1, int h1, Color color) {shearX(g, w1, h1, color);shearY(g, w1, h1, color);}private static void shearX(Graphics g, int w1, int h1, Color color) {int period = random.nextInt(2);boolean borderGap = true;int frames = 1;int phase = random.nextInt(2);for (int i = 0; i < h1; i++) {double d = (double) (period >> 1)* Math.sin((double) i / (double) period + (6.2831853071795862D * (double) phase) / (double) frames);g.copyArea(0, i, w1, 1, (int) d, 0);if (borderGap) {g.setColor(color);g.drawLine((int) d, i, 0, i);g.drawLine((int) d + w1, i, w1, i);}}}private static void shearY(Graphics g, int w1, int h1, Color color) {int period = random.nextInt(40) + 10; // 50;boolean borderGap = true;int frames = 20;int phase = 7;for (int i = 0; i < w1; i++) {double d = (double) (period >> 1)* Math.sin((double) i / (double) period + (6.2831853071795862D * (double) phase) / (double) frames);g.copyArea(i, 0, 1, h1, 0, (int) d);if (borderGap) {g.setColor(color);g.drawLine(i, (int) d, i, 0);g.drawLine(i, (int) d + h1, i, h1);}}}
}

2.4 定义一个统一返回给前台数据的类对象

定义一个类, 用于将封装处理请求结果的数据,返回给前端页面

package com.ruoyi.framework.web.domain;/*** 操作消息提醒** @author ruoyi*/
public class AjaxResult extends HashMap<String, Object> {private static final long serialVersionUID = 1L;/*** 状态码*/public static final String CODE_TAG = "code";/*** 返回内容*/public static final String MSG_TAG = "msg";/*** 数据对象*/public static final String DATA_TAG = "data";/*** 初始化一个新创建的 AjaxResult 对象,使其表示一个空消息。*/public AjaxResult() {}/*** 初始化一个新创建的 AjaxResult 对象** @param code 状态码* @param msg  返回内容*/public AjaxResult(int code, String msg) {super.put(CODE_TAG, code);super.put(MSG_TAG, msg);}/*** 初始化一个新创建的 AjaxResult 对象** @param code 状态码* @param msg  返回内容* @param data 数据对象*/public AjaxResult(int code, String msg, Object data) {super.put(CODE_TAG, code);super.put(MSG_TAG, msg);if (StringUtils.isNotNull(data)) {super.put(DATA_TAG, data);}}/*** 返回成功消息** @return 成功消息*/public static AjaxResult success() {return AjaxResult.success("操作成功");}/*** 返回成功数据** @return 成功消息*/public static AjaxResult success(Object data) {return AjaxResult.success("操作成功", data);}/*** 返回成功消息** @param msg 返回内容* @return 成功消息*/public static AjaxResult success(String msg) {return AjaxResult.success(msg, null);}/*** 返回成功消息** @param msg  返回内容* @param data 数据对象* @return 成功消息*/public static AjaxResult success(String msg, Object data) {return new AjaxResult(HttpStatus.SUCCESS, msg, data);}/*** 返回错误消息** @return*/public static AjaxResult error() {return AjaxResult.error("操作失败");}/*** 返回错误消息** @param msg 返回内容* @return 警告消息*/public static AjaxResult error(String msg) {return AjaxResult.error(msg, null);}/*** 返回错误消息** @param msg  返回内容* @param data 数据对象* @return 警告消息*/public static AjaxResult error(String msg, Object data) {return new AjaxResult(HttpStatus.ERROR, msg, data);}/*** 返回错误消息** @param code 状态码* @param msg  返回内容* @return 警告消息*/public static AjaxResult error(int code, String msg) {return new AjaxResult(code, msg, null);}
}

2.5 定义返回状态码

package com.ruoyi.common.constant;/*** 返回状态码** @author ruoyi*/
public interface HttpStatus {/*** 操作成功*/public static final int SUCCESS = 200;/*** 对象创建成功*/public static final int CREATED = 201;/*** 请求已经被接受*/public static final int ACCEPTED = 202;/*** 操作已经执行成功,但是没有返回数据*/public static final int NO_CONTENT = 204;/*** 资源已被移除*/public static final int MOVED_PERM = 301;/*** 重定向*/public static final int SEE_OTHER = 303;/*** 资源没有被修改*/public static final int NOT_MODIFIED = 304;/*** 参数列表错误(缺少,格式不匹配)*/public static final int BAD_REQUEST = 400;/*** 未授权*/public static final int UNAUTHORIZED = 401;/*** 访问受限,授权过期*/public static final int FORBIDDEN = 403;/*** 资源,服务未找到*/public static final int NOT_FOUND = 404;/*** 不允许的http方法*/public static final int BAD_METHOD = 405;/*** 资源冲突,或者资源被锁*/public static final int CONFLICT = 409;/*** 不支持的数据,媒体类型*/public static final int UNSUPPORTED_TYPE = 415;/*** 系统内部错误*/public static final int ERROR = 500;/*** 接口未实现*/public static final int NOT_IMPLEMENTED = 501;
}

2.6 字符串的工具类

该类封装了对字符串常用操作, 若判断字符串、集合、数组、Map等类型是否为空,字符串去空格,字符串截取等操作

2.6.1 引入常用工具包

		<!--常用工具类 --><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId></dependency>

2.6.2 字符集工具类

package com.ruoyi.common.core.text;/*** 字符集工具类** @author ruoyi*/
public class CharsetKit {/*** ISO-8859-1*/public static final String ISO_8859_1 = "ISO-8859-1";/*** UTF-8*/public static final String UTF_8 = "UTF-8";/*** GBK*/public static final String GBK = "GBK";/*** ISO-8859-1*/public static final Charset CHARSET_ISO_8859_1 = Charset.forName(ISO_8859_1);/*** UTF-8*/public static final Charset CHARSET_UTF_8 = Charset.forName(UTF_8);/*** GBK*/public static final Charset CHARSET_GBK = Charset.forName(GBK);/*** 转换为Charset对象** @param charset 字符集,为空则返回默认字符集* @return Charset*/public static Charset charset(String charset) {return StringUtils.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset);}/*** 转换字符串的字符集编码** @param source      字符串* @param srcCharset  源字符集,默认ISO-8859-1* @param destCharset 目标字符集,默认UTF-8* @return 转换后的字符集*/public static String convert(String source, String srcCharset, String destCharset) {return convert(source, Charset.forName(srcCharset), Charset.forName(destCharset));}/*** 转换字符串的字符集编码** @param source      字符串* @param srcCharset  源字符集,默认ISO-8859-1* @param destCharset 目标字符集,默认UTF-8* @return 转换后的字符集*/public static String convert(String source, Charset srcCharset, Charset destCharset) {if (null == srcCharset) {srcCharset = StandardCharsets.ISO_8859_1;}if (null == destCharset) {srcCharset = StandardCharsets.UTF_8;}if (StringUtils.isEmpty(source) || srcCharset.equals(destCharset)) {return source;}return new String(source.getBytes(srcCharset), destCharset);}/*** @return 系统字符集编码*/public static String systemCharset() {return Charset.defaultCharset().name();}
}

2.6.3 类型转换器

package com.ruoyi.common.core.text;/*** 类型转换器** @author ruoyi*/
public class Convert {/*** 转换为字符串<br>* 如果给定的值为null,或者转换失败,返回默认值<br>* 转换失败不会报错** @param value        被转换的值* @param defaultValue 转换错误时的默认值* @return 结果*/public static String toStr(Object value, String defaultValue) {if (null == value) {return defaultValue;}if (value instanceof String) {return (String) value;}return value.toString();}/*** 转换为字符串<br>* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>* 转换失败不会报错** @param value 被转换的值* @return 结果*/public static String toStr(Object value) {return toStr(value, null);}/*** 转换为字符<br>* 如果给定的值为null,或者转换失败,返回默认值<br>* 转换失败不会报错** @param value        被转换的值* @param defaultValue 转换错误时的默认值* @return 结果*/public static Character toChar(Object value, Character defaultValue) {if (null == value) {return defaultValue;}if (value instanceof Character) {return (Character) value;}final String valueStr = toStr(value, null);return StringUtils.isEmpty(valueStr) ? defaultValue : valueStr.charAt(0);}/*** 转换为字符<br>* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>* 转换失败不会报错** @param value 被转换的值* @return 结果*/public static Character toChar(Object value) {return toChar(value, null);}/*** 转换为byte<br>* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<br>* 转换失败不会报错** @param value        被转换的值* @param defaultValue 转换错误时的默认值* @return 结果*/public static Byte toByte(Object value, Byte defaultValue) {if (value == null) {return defaultValue;}if (value instanceof Byte) {return (Byte) value;}if (value instanceof Number) {return ((Number) value).byteValue();}final String valueStr = toStr(value, null);if (StringUtils.isEmpty(valueStr)) {return defaultValue;}try {return Byte.parseByte(valueStr);} catch (Exception e) {return defaultValue;}}/*** 转换为byte<br>* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>* 转换失败不会报错** @param value 被转换的值* @return 结果*/public static Byte toByte(Object value) {return toByte(value, null);}/*** 转换为Short<br>* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<br>* 转换失败不会报错** @param value        被转换的值* @param defaultValue 转换错误时的默认值* @return 结果*/public static Short toShort(Object value, Short defaultValue) {if (value == null) {return defaultValue;}if (value instanceof Short) {return (Short) value;}if (value instanceof Number) {return ((Number) value).shortValue();}final String valueStr = toStr(value, null);if (StringUtils.isEmpty(valueStr)) {return defaultValue;}try {return Short.parseShort(valueStr.trim());} catch (Exception e) {return defaultValue;}}/*** 转换为Short<br>* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>* 转换失败不会报错** @param value 被转换的值* @return 结果*/public static Short toShort(Object value) {return toShort(value, null);}/*** 转换为Number<br>* 如果给定的值为空,或者转换失败,返回默认值<br>* 转换失败不会报错** @param value        被转换的值* @param defaultValue 转换错误时的默认值* @return 结果*/public static Number toNumber(Object value, Number defaultValue) {if (value == null) {return defaultValue;}if (value instanceof Number) {return (Number) value;}final String valueStr = toStr(value, null);if (StringUtils.isEmpty(valueStr)) {return defaultValue;}try {return NumberFormat.getInstance().parse(valueStr);} catch (Exception e) {return defaultValue;}}/*** 转换为Number<br>* 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>* 转换失败不会报错** @param value 被转换的值* @return 结果*/public static Number toNumber(Object value) {return toNumber(value, null);}/*** 转换为int<br>* 如果给定的值为空,或者转换失败,返回默认值<br>* 转换失败不会报错** @param value        被转换的值* @param defaultValue 转换错误时的默认值* @return 结果*/public static Integer toInt(Object value, Integer defaultValue) {if (value == null) {return defaultValue;}if (value instanceof Integer) {return (Integer) value;}if (value instanceof Number) {return ((Number) value).intValue();}final String valueStr = toStr(value, null);if (StringUtils.isEmpty(valueStr)) {return defaultValue;}try {return Integer.parseInt(valueStr.trim());} catch (Exception e) {return defaultValue;}}/*** 转换为int<br>* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>* 转换失败不会报错** @param value 被转换的值* @return 结果*/public static Integer toInt(Object value) {return toInt(value, null);}/*** 转换为Integer数组<br>** @param str 被转换的值* @return 结果*/public static Integer[] toIntArray(String str) {return toIntArray(",", str);}/*** 转换为Long数组<br>** @param str 被转换的值* @return 结果*/public static Long[] toLongArray(String str) {return toLongArray(",", str);}/*** 转换为Integer数组<br>** @param split 分隔符* @param split 被转换的值* @return 结果*/public static Integer[] toIntArray(String split, String str) {if (StringUtils.isEmpty(str)) {return new Integer[]{};}String[] arr = str.split(split);final Integer[] ints = new Integer[arr.length];for (int i = 0; i < arr.length; i++) {final Integer v = toInt(arr[i], 0);ints[i] = v;}return ints;}/*** 转换为Long数组<br>** @param split 分隔符* @param str   被转换的值* @return 结果*/public static Long[] toLongArray(String split, String str) {if (StringUtils.isEmpty(str)) {return new Long[]{};}String[] arr = str.split(split);final Long[] longs = new Long[arr.length];for (int i = 0; i < arr.length; i++) {final Long v = toLong(arr[i], null);longs[i] = v;}return longs;}/*** 转换为String数组<br>** @param str 被转换的值* @return 结果*/public static String[] toStrArray(String str) {return toStrArray(",", str);}/*** 转换为String数组<br>** @param split 分隔符* @param split 被转换的值* @return 结果*/public static String[] toStrArray(String split, String str) {return str.split(split);}/*** 转换为long<br>* 如果给定的值为空,或者转换失败,返回默认值<br>* 转换失败不会报错** @param value        被转换的值* @param defaultValue 转换错误时的默认值* @return 结果*/public static Long toLong(Object value, Long defaultValue) {if (value == null) {return defaultValue;}if (value instanceof Long) {return (Long) value;}if (value instanceof Number) {return ((Number) value).longValue();}final String valueStr = toStr(value, null);if (StringUtils.isEmpty(valueStr)) {return defaultValue;}try {// 支持科学计数法return new BigDecimal(valueStr.trim()).longValue();} catch (Exception e) {return defaultValue;}}/*** 转换为long<br>* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>* 转换失败不会报错** @param value 被转换的值* @return 结果*/public static Long toLong(Object value) {return toLong(value, null);}/*** 转换为double<br>* 如果给定的值为空,或者转换失败,返回默认值<br>* 转换失败不会报错** @param value        被转换的值* @param defaultValue 转换错误时的默认值* @return 结果*/public static Double toDouble(Object value, Double defaultValue) {if (value == null) {return defaultValue;}if (value instanceof Double) {return (Double) value;}if (value instanceof Number) {return ((Number) value).doubleValue();}final String valueStr = toStr(value, null);if (StringUtils.isEmpty(valueStr)) {return defaultValue;}try {// 支持科学计数法return new BigDecimal(valueStr.trim()).doubleValue();} catch (Exception e) {return defaultValue;}}/*** 转换为double<br>* 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>* 转换失败不会报错** @param value 被转换的值* @return 结果*/public static Double toDouble(Object value) {return toDouble(value, null);}/*** 转换为Float<br>* 如果给定的值为空,或者转换失败,返回默认值<br>* 转换失败不会报错** @param value        被转换的值* @param defaultValue 转换错误时的默认值* @return 结果*/public static Float toFloat(Object value, Float defaultValue) {if (value == null) {return defaultValue;}if (value instanceof Float) {return (Float) value;}if (value instanceof Number) {return ((Number) value).floatValue();}final String valueStr = toStr(value, null);if (StringUtils.isEmpty(valueStr)) {return defaultValue;}try {return Float.parseFloat(valueStr.trim());} catch (Exception e) {return defaultValue;}}/*** 转换为Float<br>* 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>* 转换失败不会报错** @param value 被转换的值* @return 结果*/public static Float toFloat(Object value) {return toFloat(value, null);}/*** 转换为boolean<br>* String支持的值为:true、false、yes、ok、no,1,0 如果给定的值为空,或者转换失败,返回默认值<br>* 转换失败不会报错** @param value        被转换的值* @param defaultValue 转换错误时的默认值* @return 结果*/public static Boolean toBool(Object value, Boolean defaultValue) {if (value == null) {return defaultValue;}if (value instanceof Boolean) {return (Boolean) value;}String valueStr = toStr(value, null);if (StringUtils.isEmpty(valueStr)) {return defaultValue;}valueStr = valueStr.trim().toLowerCase();switch (valueStr) {case "true":return true;case "false":return false;case "yes":return true;case "ok":return true;case "no":return false;case "1":return true;case "0":return false;default:return defaultValue;}}/*** 转换为boolean<br>* 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>* 转换失败不会报错** @param value 被转换的值* @return 结果*/public static Boolean toBool(Object value) {return toBool(value, null);}/*** 转换为Enum对象<br>* 如果给定的值为空,或者转换失败,返回默认值<br>** @param clazz        Enum的Class* @param value        值* @param defaultValue 默认值* @return Enum*/public static <E extends Enum<E>> E toEnum(Class<E> clazz, Object value, E defaultValue) {if (value == null) {return defaultValue;}if (clazz.isAssignableFrom(value.getClass())) {@SuppressWarnings("unchecked")E myE = (E) value;return myE;}final String valueStr = toStr(value, null);if (StringUtils.isEmpty(valueStr)) {return defaultValue;}try {return Enum.valueOf(clazz, valueStr);} catch (Exception e) {return defaultValue;}}/*** 转换为Enum对象<br>* 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>** @param clazz Enum的Class* @param value 值* @return Enum*/public static <E extends Enum<E>> E toEnum(Class<E> clazz, Object value) {return toEnum(clazz, value, null);}/*** 转换为BigInteger<br>* 如果给定的值为空,或者转换失败,返回默认值<br>* 转换失败不会报错** @param value        被转换的值* @param defaultValue 转换错误时的默认值* @return 结果*/public static BigInteger toBigInteger(Object value, BigInteger defaultValue) {if (value == null) {return defaultValue;}if (value instanceof BigInteger) {return (BigInteger) value;}if (value instanceof Long) {return BigInteger.valueOf((Long) value);}final String valueStr = toStr(value, null);if (StringUtils.isEmpty(valueStr)) {return defaultValue;}try {return new BigInteger(valueStr);} catch (Exception e) {return defaultValue;}}/*** 转换为BigInteger<br>* 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>* 转换失败不会报错** @param value 被转换的值* @return 结果*/public static BigInteger toBigInteger(Object value) {return toBigInteger(value, null);}/*** 转换为BigDecimal<br>* 如果给定的值为空,或者转换失败,返回默认值<br>* 转换失败不会报错** @param value        被转换的值* @param defaultValue 转换错误时的默认值* @return 结果*/public static BigDecimal toBigDecimal(Object value, BigDecimal defaultValue) {if (value == null) {return defaultValue;}if (value instanceof BigDecimal) {return (BigDecimal) value;}if (value instanceof Long) {return new BigDecimal((Long) value);}if (value instanceof Double) {return new BigDecimal((Double) value);}if (value instanceof Integer) {return new BigDecimal((Integer) value);}final String valueStr = toStr(value, null);if (StringUtils.isEmpty(valueStr)) {return defaultValue;}try {return new BigDecimal(valueStr);} catch (Exception e) {return defaultValue;}}/*** 转换为BigDecimal<br>* 如果给定的值为空,或者转换失败,返回默认值<br>* 转换失败不会报错** @param value 被转换的值* @return 结果*/public static BigDecimal toBigDecimal(Object value) {return toBigDecimal(value, null);}/*** 将对象转为字符串<br>* 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法** @param obj 对象* @return 字符串*/public static String utf8Str(Object obj) {return str(obj, CharsetKit.CHARSET_UTF_8);}/*** 将对象转为字符串<br>* 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法** @param obj         对象* @param charsetName 字符集* @return 字符串*/public static String str(Object obj, String charsetName) {return str(obj, Charset.forName(charsetName));}/*** 将对象转为字符串<br>* 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法** @param obj     对象* @param charset 字符集* @return 字符串*/public static String str(Object obj, Charset charset) {if (null == obj) {return null;}if (obj instanceof String) {return (String) obj;} else if (obj instanceof byte[] || obj instanceof Byte[]) {return str((Byte[]) obj, charset);} else if (obj instanceof ByteBuffer) {return str((ByteBuffer) obj, charset);}return obj.toString();}/*** 将byte数组转为字符串** @param bytes   byte数组* @param charset 字符集* @return 字符串*/public static String str(byte[] bytes, String charset) {return str(bytes, StringUtils.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset));}/*** 解码字节码** @param data    字符串* @param charset 字符集,如果此字段为空,则解码的结果取决于平台* @return 解码后的字符串*/public static String str(byte[] data, Charset charset) {if (data == null) {return null;}if (null == charset) {return new String(data);}return new String(data, charset);}/*** 将编码的byteBuffer数据转换为字符串** @param data    数据* @param charset 字符集,如果为空使用当前系统字符集* @return 字符串*/public static String str(ByteBuffer data, String charset) {if (data == null) {return null;}return str(data, Charset.forName(charset));}/*** 将编码的byteBuffer数据转换为字符串** @param data    数据* @param charset 字符集,如果为空使用当前系统字符集* @return 字符串*/public static String str(ByteBuffer data, Charset charset) {if (null == charset) {charset = Charset.defaultCharset();}return charset.decode(data).toString();}// ----------------------------------------------------------------------- 全角半角转换/*** 半角转全角** @param input String.* @return 全角字符串.*/public static String toSBC(String input) {return toSBC(input, null);}/*** 半角转全角** @param input         String* @param notConvertSet 不替换的字符集合* @return 全角字符串.*/public static String toSBC(String input, Set<Character> notConvertSet) {char c[] = input.toCharArray();for (int i = 0; i < c.length; i++) {if (null != notConvertSet && notConvertSet.contains(c[i])) {// 跳过不替换的字符continue;}if (c[i] == ' ') {c[i] = '\u3000';} else if (c[i] < '\177') {c[i] = (char) (c[i] + 65248);}}return new String(c);}/*** 全角转半角** @param input String.* @return 半角字符串*/public static String toDBC(String input) {return toDBC(input, null);}/*** 替换全角为半角** @param text          文本* @param notConvertSet 不替换的字符集合* @return 替换后的字符*/public static String toDBC(String text, Set<Character> notConvertSet) {char c[] = text.toCharArray();for (int i = 0; i < c.length; i++) {if (null != notConvertSet && notConvertSet.contains(c[i])) {// 跳过不替换的字符continue;}if (c[i] == '\u3000') {c[i] = ' ';} else if (c[i] > '\uFF00' && c[i] < '\uFF5F') {c[i] = (char) (c[i] - 65248);}}String returnString = new String(c);return returnString;}/*** 数字金额大写转换 先写个完整的然后将如零拾替换成零** @param n 数字* @return 中文大写数字*/public static String digitUppercase(double n) {String[] fraction = {"角", "分"};String[] digit = {"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"};String[][] unit = {{"元", "万", "亿"}, {"", "拾", "佰", "仟"}};String head = n < 0 ? "负" : "";n = Math.abs(n);String s = "";for (int i = 0; i < fraction.length; i++) {s += (digit[(int) (Math.floor(n * 10 * Math.pow(10, i)) % 10)] + fraction[i]).replaceAll("(零.)+", "");}if (s.length() < 1) {s = "整";}int integerPart = (int) Math.floor(n);for (int i = 0; i < unit[0].length && integerPart > 0; i++) {String p = "";for (int j = 0; j < unit[1].length && n > 0; j++) {p = digit[integerPart % 10] + unit[1][j] + p;integerPart = integerPart / 10;}s = p.replaceAll("(零.)*零$", "").replaceAll("^$", "零") + unit[0][i] + s;}return head + s.replaceAll("(零.)*零元", "元").replaceFirst("(零.)+", "").replaceAll("(零.)+", "零").replaceAll("^整$", "零元整");}
}

2.6.4 字符串格式化

package com.ruoyi.common.core.text;/*** 字符串格式化** @author ruoyi*/
public class StrFormatter {public static final String EMPTY_JSON = "{}";public static final char C_BACKSLASH = '\\';public static final char C_DELIM_START = '{';public static final char C_DELIM_END = '}';/*** 格式化字符串<br>* 此方法只是简单将占位符 {} 按照顺序替换为参数<br>* 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可<br>* 例:<br>* 通常使用:format("this is {} for {}", "a", "b") -> this is a for b<br>* 转义{}: format("this is \\{} for {}", "a", "b") -> this is \{} for a<br>* 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br>** @param strPattern 字符串模板* @param argArray   参数列表* @return 结果*/public static String format(final String strPattern, final Object... argArray) {if (StringUtils.isEmpty(strPattern) || StringUtils.isEmpty(argArray)) {return strPattern;}final int strPatternLength = strPattern.length();// 初始化定义好的长度以获得更好的性能StringBuilder sbuf = new StringBuilder(strPatternLength + 50);int handledPosition = 0;int delimIndex;// 占位符所在位置for (int argIndex = 0; argIndex < argArray.length; argIndex++) {delimIndex = strPattern.indexOf(EMPTY_JSON, handledPosition);if (delimIndex == -1) {if (handledPosition == 0) {return strPattern;} else { // 字符串模板剩余部分不再包含占位符,加入剩余部分后返回结果sbuf.append(strPattern, handledPosition, strPatternLength);return sbuf.toString();}} else {if (delimIndex > 0 && strPattern.charAt(delimIndex - 1) == C_BACKSLASH) {if (delimIndex > 1 && strPattern.charAt(delimIndex - 2) == C_BACKSLASH) {// 转义符之前还有一个转义符,占位符依旧有效sbuf.append(strPattern, handledPosition, delimIndex - 1);sbuf.append(Convert.utf8Str(argArray[argIndex]));handledPosition = delimIndex + 2;} else {// 占位符被转义argIndex--;sbuf.append(strPattern, handledPosition, delimIndex - 1);sbuf.append(C_DELIM_START);handledPosition = delimIndex + 1;}} else {// 正常占位符sbuf.append(strPattern, handledPosition, delimIndex);sbuf.append(Convert.utf8Str(argArray[argIndex]));handledPosition = delimIndex + 2;}}}// 加入最后一个占位符后所有的字符sbuf.append(strPattern, handledPosition, strPattern.length());return sbuf.toString();}
}

2.6.5 字符串工具类

package com.ruoyi.common.utils;/*** 字符串工具类** @author ruoyi*/
public class StringUtils extends org.apache.commons.lang3.StringUtils {/*** 空字符串*/private static final String NULLSTR = "";/*** 下划线*/private static final char SEPARATOR = '_';/*** 获取参数不为空值** @param value defaultValue 要判断的value* @return value 返回值*/public static <T> T nvl(T value, T defaultValue) {return value != null ? value : defaultValue;}/*** * 判断一个Collection是否为空, 包含List,Set,Queue** @param coll 要判断的Collection* @return true:为空 false:非空*/public static boolean isEmpty(Collection<?> coll) {return isNull(coll) || coll.isEmpty();}/*** * 判断一个Collection是否非空,包含List,Set,Queue** @param coll 要判断的Collection* @return true:非空 false:空*/public static boolean isNotEmpty(Collection<?> coll) {return !isEmpty(coll);}/*** * 判断一个对象数组是否为空** @param objects 要判断的对象数组*                * @return true:为空 false:非空*/public static boolean isEmpty(Object[] objects) {return isNull(objects) || (objects.length == 0);}/*** * 判断一个对象数组是否非空** @param objects 要判断的对象数组* @return true:非空 false:空*/public static boolean isNotEmpty(Object[] objects) {return !isEmpty(objects);}/*** * 判断一个Map是否为空** @param map 要判断的Map* @return true:为空 false:非空*/public static boolean isEmpty(Map<?, ?> map) {return isNull(map) || map.isEmpty();}/*** * 判断一个Map是否为空** @param map 要判断的Map* @return true:非空 false:空*/public static boolean isNotEmpty(Map<?, ?> map) {return !isEmpty(map);}/*** * 判断一个字符串是否为空串** @param str String* @return true:为空 false:非空*/public static boolean isEmpty(String str) {return isNull(str) || NULLSTR.equals(str.trim());}/*** * 判断一个字符串是否为非空串** @param str String* @return true:非空串 false:空串*/public static boolean isNotEmpty(String str) {return !isEmpty(str);}/*** * 判断一个对象是否为空** @param object Object* @return true:为空 false:非空*/public static boolean isNull(Object object) {return object == null;}/*** * 判断一个对象是否非空** @param object Object* @return true:非空 false:空*/public static boolean isNotNull(Object object) {return !isNull(object);}/*** * 判断一个对象是否是数组类型(Java基本型别的数组)** @param object 对象* @return true:是数组 false:不是数组*/public static boolean isArray(Object object) {return isNotNull(object) && object.getClass().isArray();}/*** 去空格*/public static String trim(String str) {return (str == null ? "" : str.trim());}/*** 截取字符串** @param str   字符串* @param start 开始* @return 结果*/public static String substring(final String str, int start) {if (str == null) {return NULLSTR;}if (start < 0) {start = str.length() + start;}if (start < 0) {start = 0;}if (start > str.length()) {return NULLSTR;}return str.substring(start);}/*** 截取字符串** @param str   字符串* @param start 开始* @param end   结束* @return 结果*/public static String substring(final String str, int start, int end) {if (str == null) {return NULLSTR;}if (end < 0) {end = str.length() + end;}if (start < 0) {start = str.length() + start;}if (end > str.length()) {end = str.length();}if (start > end) {return NULLSTR;}if (start < 0) {start = 0;}if (end < 0) {end = 0;}return str.substring(start, end);}/*** 格式化文本, {} 表示占位符<br>* 此方法只是简单将占位符 {} 按照顺序替换为参数<br>* 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可<br>* 例:<br>* 通常使用:format("this is {} for {}", "a", "b") -> this is a for b<br>* 转义{}: format("this is \\{} for {}", "a", "b") -> this is \{} for a<br>* 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br>** @param template 文本模板,被替换的部分用 {} 表示* @param params   参数值* @return 格式化后的文本*/public static String format(String template, Object... params) {if (isEmpty(params) || isEmpty(template)) {return template;}return StrFormatter.format(template, params);}/*** 字符串转set** @param str 字符串* @param sep 分隔符* @return set集合*/public static final Set<String> str2Set(String str, String sep) {return new HashSet<String>(str2List(str, sep, true, false));}/*** 字符串转list** @param str         字符串* @param sep         分隔符* @param filterBlank 过滤纯空白* @param trim        去掉首尾空白* @return list集合*/public static final List<String> str2List(String str, String sep, boolean filterBlank, boolean trim) {List<String> list = new ArrayList<String>();if (StringUtils.isEmpty(str)) {return list;}// 过滤空白字符串if (filterBlank && StringUtils.isBlank(str)) {return list;}String[] split = str.split(sep);for (String string : split) {if (filterBlank && StringUtils.isBlank(string)) {continue;}if (trim) {string = string.trim();}list.add(string);}return list;}/*** 下划线转驼峰命名*/public static String toUnderScoreCase(String str) {if (str == null) {return null;}StringBuilder sb = new StringBuilder();// 前置字符是否大写boolean preCharIsUpperCase = true;// 当前字符是否大写boolean curreCharIsUpperCase = true;// 下一字符是否大写boolean nexteCharIsUpperCase = true;for (int i = 0; i < str.length(); i++) {char c = str.charAt(i);if (i > 0) {preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1));} else {preCharIsUpperCase = false;}curreCharIsUpperCase = Character.isUpperCase(c);if (i < (str.length() - 1)) {nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1));}if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase) {sb.append(SEPARATOR);} else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase) {sb.append(SEPARATOR);}sb.append(Character.toLowerCase(c));}return sb.toString();}/*** 是否包含字符串** @param str  验证字符串* @param strs 字符串组* @return 包含返回true*/public static boolean inStringIgnoreCase(String str, String... strs) {if (str != null && strs != null) {for (String s : strs) {if (str.equalsIgnoreCase(trim(s))) {return true;}}}return false;}/*** 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。 例如:HELLO_WORLD->HelloWorld** @param name 转换前的下划线大写方式命名的字符串* @return 转换后的驼峰式命名的字符串*/public static String convertToCamelCase(String name) {StringBuilder result = new StringBuilder();// 快速检查if (name == null || name.isEmpty()) {// 没必要转换return "";} else if (!name.contains("_")) {// 不含下划线,仅将首字母大写return name.substring(0, 1).toUpperCase() + name.substring(1);}// 用下划线将原始字符串分割String[] camels = name.split("_");for (String camel : camels) {// 跳过原始字符串中开头、结尾的下换线或双重下划线if (camel.isEmpty()) {continue;}// 首字母大写result.append(camel.substring(0, 1).toUpperCase());result.append(camel.substring(1).toLowerCase());}return result.toString();}/*** 驼峰式命名法 例如:user_name->userName*/public static String toCamelCase(String s) {if (s == null) {return null;}s = s.toLowerCase();StringBuilder sb = new StringBuilder(s.length());boolean upperCase = false;for (int i = 0; i < s.length(); i++) {char c = s.charAt(i);if (c == SEPARATOR) {upperCase = true;} else if (upperCase) {sb.append(Character.toUpperCase(c));upperCase = false;} else {sb.append(c);}}return sb.toString();}
}

2.7 UUID生成工具类

定义一个 UUID 类

package com.ruoyi.common.core.lang;/*** 提供通用唯一识别码(universally unique identifier)(UUID)实现** @author ruoyi*/
public final class UUID implements java.io.Serializable, Comparable<UUID> {private static final long serialVersionUID = -1185015143654744140L;/*** SecureRandom 的单例*/private static class Holder {static final SecureRandom numberGenerator = getSecureRandom();}/*** 此UUID的最高64有效位*/private final long mostSigBits;/*** 此UUID的最低64有效位*/private final long leastSigBits;/*** 私有构造** @param data 数据*/private UUID(byte[] data) {long msb = 0;long lsb = 0;assert data.length == 16 : "data must be 16 bytes in length";for (int i = 0; i < 8; i++) {msb = (msb << 8) | (data[i] & 0xff);}for (int i = 8; i < 16; i++) {lsb = (lsb << 8) | (data[i] & 0xff);}this.mostSigBits = msb;this.leastSigBits = lsb;}/*** 使用指定的数据构造新的 UUID。** @param mostSigBits  用于 {@code UUID} 的最高有效 64 位* @param leastSigBits 用于 {@code UUID} 的最低有效 64 位*/public UUID(long mostSigBits, long leastSigBits) {this.mostSigBits = mostSigBits;this.leastSigBits = leastSigBits;}/*** 获取类型 4(伪随机生成的)UUID 的静态工厂。 使用加密的本地线程伪随机数生成器生成该 UUID。** @return 随机生成的 {@code UUID}*/public static UUID fastUUID() {return randomUUID(false);}/*** 获取类型 4(伪随机生成的)UUID 的静态工厂。 使用加密的强伪随机数生成器生成该 UUID。** @return 随机生成的 {@code UUID}*/public static UUID randomUUID() {return randomUUID(true);}/*** 获取类型 4(伪随机生成的)UUID 的静态工厂。 使用加密的强伪随机数生成器生成该 UUID。** @param isSecure 是否使用{@link SecureRandom}如果是可以获得更安全的随机码,否则可以得到更好的性能* @return 随机生成的 {@code UUID}*/public static UUID randomUUID(boolean isSecure) {final Random ng = isSecure ? Holder.numberGenerator : getRandom();byte[] randomBytes = new byte[16];ng.nextBytes(randomBytes);randomBytes[6] &= 0x0f; /* clear version */randomBytes[6] |= 0x40; /* set to version 4 */randomBytes[8] &= 0x3f; /* clear variant */randomBytes[8] |= 0x80; /* set to IETF variant */return new UUID(randomBytes);}/*** 根据指定的字节数组获取类型 3(基于名称的)UUID 的静态工厂。** @param name 用于构造 UUID 的字节数组。* @return 根据指定数组生成的 {@code UUID}*/public static UUID nameUUIDFromBytes(byte[] name) {MessageDigest md;try {md = MessageDigest.getInstance("MD5");} catch (NoSuchAlgorithmException nsae) {throw new InternalError("MD5 not supported");}byte[] md5Bytes = md.digest(name);md5Bytes[6] &= 0x0f; /* clear version */md5Bytes[6] |= 0x30; /* set to version 3 */md5Bytes[8] &= 0x3f; /* clear variant */md5Bytes[8] |= 0x80; /* set to IETF variant */return new UUID(md5Bytes);}/*** 根据 {@link #toString()} 方法中描述的字符串标准表示形式创建{@code UUID}。** @param name 指定 {@code UUID} 字符串* @return 具有指定值的 {@code UUID}* @throws IllegalArgumentException 如果 name 与 {@link #toString} 中描述的字符串表示形式不符抛出此异常*/public static UUID fromString(String name) {String[] components = name.split("-");if (components.length != 5) {throw new IllegalArgumentException("Invalid UUID string: " + name);}for (int i = 0; i < 5; i++) {components[i] = "0x" + components[i];}long mostSigBits = Long.decode(components[0]).longValue();mostSigBits <<= 16;mostSigBits |= Long.decode(components[1]).longValue();mostSigBits <<= 16;mostSigBits |= Long.decode(components[2]).longValue();long leastSigBits = Long.decode(components[3]).longValue();leastSigBits <<= 48;leastSigBits |= Long.decode(components[4]).longValue();return new UUID(mostSigBits, leastSigBits);}/*** 返回此 UUID 的 128 位值中的最低有效 64 位。** @return 此 UUID 的 128 位值中的最低有效 64 位。*/public long getLeastSignificantBits() {return leastSigBits;}/*** 返回此 UUID 的 128 位值中的最高有效 64 位。** @return 此 UUID 的 128 位值中最高有效 64 位。*/public long getMostSignificantBits() {return mostSigBits;}/*** 与此 {@code UUID} 相关联的版本号. 版本号描述此 {@code UUID} 是如何生成的。* <p>* 版本号具有以下含意:* <ul>* <li>1 基于时间的 UUID* <li>2 DCE 安全 UUID* <li>3 基于名称的 UUID* <li>4 随机生成的 UUID* </ul>** @return 此 {@code UUID} 的版本号*/public int version() {// Version is bits masked by 0x000000000000F000 in MS longreturn (int) ((mostSigBits >> 12) & 0x0f);}/*** 与此 {@code UUID} 相关联的变体号。变体号描述 {@code UUID} 的布局。* <p>* 变体号具有以下含意:* <ul>* <li>0 为 NCS 向后兼容保留* <li>2 <a href="http://www.ietf.org/rfc/rfc4122.txt">IETF&nbsp;RFC&nbsp;4122</a>(Leach-Salz), 用于此类* <li>6 保留,微软向后兼容* <li>7 保留供以后定义使用* </ul>** @return 此 {@code UUID} 相关联的变体号*/public int variant() {// This field is composed of a varying number of bits.// 0 - - Reserved for NCS backward compatibility// 1 0 - The IETF aka Leach-Salz variant (used by this class)// 1 1 0 Reserved, Microsoft backward compatibility// 1 1 1 Reserved for future definition.return (int) ((leastSigBits >>> (64 - (leastSigBits >>> 62))) & (leastSigBits >> 63));}/*** 与此 UUID 相关联的时间戳值。** <p>* 60 位的时间戳值根据此 {@code UUID} 的 time_low、time_mid 和 time_hi 字段构造。<br>* 所得到的时间戳以 100 毫微秒为单位,从 UTC(通用协调时间) 1582 年 10 月 15 日零时开始。** <p>* 时间戳值仅在在基于时间的 UUID(其 version 类型为 1)中才有意义。<br>* 如果此 {@code UUID} 不是基于时间的 UUID,则此方法抛出 UnsupportedOperationException。** @throws UnsupportedOperationException 如果此 {@code UUID} 不是 version 为 1 的 UUID。*/public long timestamp() throws UnsupportedOperationException {checkTimeBase();return (mostSigBits & 0x0FFFL) << 48//| ((mostSigBits >> 16) & 0x0FFFFL) << 32//| mostSigBits >>> 32;}/*** 与此 UUID 相关联的时钟序列值。** <p>* 14 位的时钟序列值根据此 UUID 的 clock_seq 字段构造。clock_seq 字段用于保证在基于时间的 UUID 中的时间唯一性。* <p>* {@code clockSequence} 值仅在基于时间的 UUID(其 version 类型为 1)中才有意义。 如果此 UUID 不是基于时间的 UUID,则此方法抛出* UnsupportedOperationException。** @return 此 {@code UUID} 的时钟序列* @throws UnsupportedOperationException 如果此 UUID 的 version 不为 1*/public int clockSequence() throws UnsupportedOperationException {checkTimeBase();return (int) ((leastSigBits & 0x3FFF000000000000L) >>> 48);}/*** 与此 UUID 相关的节点值。** <p>* 48 位的节点值根据此 UUID 的 node 字段构造。此字段旨在用于保存机器的 IEEE 802 地址,该地址用于生成此 UUID 以保证空间唯一性。* <p>* 节点值仅在基于时间的 UUID(其 version 类型为 1)中才有意义。<br>* 如果此 UUID 不是基于时间的 UUID,则此方法抛出 UnsupportedOperationException。** @return 此 {@code UUID} 的节点值* @throws UnsupportedOperationException 如果此 UUID 的 version 不为 1*/public long node() throws UnsupportedOperationException {checkTimeBase();return leastSigBits & 0x0000FFFFFFFFFFFFL;}/*** 返回此{@code UUID} 的字符串表现形式。** <p>* UUID 的字符串表示形式由此 BNF 描述:** <pre>* {@code* UUID                   = <time_low>-<time_mid>-<time_high_and_version>-<variant_and_sequence>-<node>* time_low               = 4*<hexOctet>* time_mid               = 2*<hexOctet>* time_high_and_version  = 2*<hexOctet>* variant_and_sequence   = 2*<hexOctet>* node                   = 6*<hexOctet>* hexOctet               = <hexDigit><hexDigit>* hexDigit               = [0-9a-fA-F]* }* </pre>** </blockquote>** @return 此{@code UUID} 的字符串表现形式* @see #toString(boolean)*/@Overridepublic String toString() {return toString(false);}/*** 返回此{@code UUID} 的字符串表现形式。** <p>* UUID 的字符串表示形式由此 BNF 描述:** <pre>* {@code* UUID                   = <time_low>-<time_mid>-<time_high_and_version>-<variant_and_sequence>-<node>* time_low               = 4*<hexOctet>* time_mid               = 2*<hexOctet>* time_high_and_version  = 2*<hexOctet>* variant_and_sequence   = 2*<hexOctet>* node                   = 6*<hexOctet>* hexOctet               = <hexDigit><hexDigit>* hexDigit               = [0-9a-fA-F]* }* </pre>** </blockquote>** @param isSimple 是否简单模式,简单模式为不带'-'的UUID字符串* @return 此{@code UUID} 的字符串表现形式*/public String toString(boolean isSimple) {final StringBuilder builder = new StringBuilder(isSimple ? 32 : 36);// time_lowbuilder.append(digits(mostSigBits >> 32, 8));if (false == isSimple) {builder.append('-');}// time_midbuilder.append(digits(mostSigBits >> 16, 4));if (false == isSimple) {builder.append('-');}// time_high_and_versionbuilder.append(digits(mostSigBits, 4));if (false == isSimple) {builder.append('-');}// variant_and_sequencebuilder.append(digits(leastSigBits >> 48, 4));if (false == isSimple) {builder.append('-');}// nodebuilder.append(digits(leastSigBits, 12));return builder.toString();}/*** 返回此 UUID 的哈希码。** @return UUID 的哈希码值。*/public int hashCode() {long hilo = mostSigBits ^ leastSigBits;return ((int) (hilo >> 32)) ^ (int) hilo;}/*** 将此对象与指定对象比较。* <p>* 当且仅当参数不为 {@code null}、而是一个 UUID 对象、具有与此 UUID 相同的 varriant、包含相同的值(每一位均相同)时,结果才为 {@code true}。** @param obj 要与之比较的对象* @return 如果对象相同,则返回 {@code true};否则返回 {@code false}*/public boolean equals(Object obj) {if ((null == obj) || (obj.getClass() != UUID.class)) {return false;}UUID id = (UUID) obj;return (mostSigBits == id.mostSigBits && leastSigBits == id.leastSigBits);}// Comparison Operations/*** 将此 UUID 与指定的 UUID 比较。** <p>* 如果两个 UUID 不同,且第一个 UUID 的最高有效字段大于第二个 UUID 的对应字段,则第一个 UUID 大于第二个 UUID。** @param val 与此 UUID 比较的 UUID* @return 在此 UUID 小于、等于或大于 val 时,分别返回 -1、0 或 1。*/public int compareTo(UUID val) {// The ordering is intentionally set up so that the UUIDs// can simply be numerically compared as two numbersreturn (this.mostSigBits < val.mostSigBits ? -1 : //(this.mostSigBits > val.mostSigBits ? 1 : //(this.leastSigBits < val.leastSigBits ? -1 : //(this.leastSigBits > val.leastSigBits ? 1 : //0))));}// -------------------------------------------------------------------------------------------------------------------// Private method start/*** 返回指定数字对应的hex值** @param val    值* @param digits 位* @return 值*/private static String digits(long val, int digits) {long hi = 1L << (digits * 4);return Long.toHexString(hi | (val & (hi - 1))).substring(1);}/*** 检查是否为time-based版本UUID*/private void checkTimeBase() {if (version() != 1) {throw new UnsupportedOperationException("Not a time-based UUID");}}/*** 获取{@link SecureRandom},类提供加密的强随机数生成器 (RNG)** @return {@link SecureRandom}*/public static SecureRandom getSecureRandom() {try {return SecureRandom.getInstance("SHA1PRNG");} catch (NoSuchAlgorithmException e) {throw new RuntimeException(e);}}/*** 获取随机数生成器对象<br>* ThreadLocalRandom是JDK 7之后提供并发产生随机数,能够解决多个线程发生的竞争争夺。** @return {@link ThreadLocalRandom}*/public static ThreadLocalRandom getRandom() {return ThreadLocalRandom.current();}
}
ID生成器工具类
package com.ruoyi.common.utils;/*** ID生成器工具类** @author ruoyi*/
public class IdUtils {/*** 获取随机UUID** @return 随机UUID*/public static String randomUUID() {return UUID.randomUUID().toString();}/*** 简化的UUID,去掉了横线** @return 简化的UUID,去掉了横线*/public static String simpleUUID() {return UUID.randomUUID().toString(true);}/*** 获取随机UUID,使用性能更好的ThreadLocalRandom生成UUID** @return 随机UUID*/public static String fastUUID() {return UUID.fastUUID().toString();}/*** 简化的UUID,去掉了横线,使用性能更好的ThreadLocalRandom生成UUID** @return 简化的UUID,去掉了横线*/public static String fastSimpleUUID() {return UUID.fastUUID().toString(true);}
}

2.8 通用常量类

package com.ruoyi.common.constant;
/*** 通用常量信息** @author ruoyi*/
public class Constants {/*** UTF-8 字符集*/public static final String UTF8 = "UTF-8";/*** 通用成功标识*/public static final String SUCCESS = "0";/*** 通用失败标识*/public static final String FAIL = "1";/*** 登录成功*/public static final String LOGIN_SUCCESS = "Success";/*** 注销*/public static final String LOGOUT = "Logout";/*** 登录失败*/public static final String LOGIN_FAIL = "Error";/*** 验证码 redis key*/public static final String CAPTCHA_CODE_KEY = "captcha_codes:";/*** 登录用户 redis key*/public static final String LOGIN_TOKEN_KEY = "login_tokens:";/*** 验证码有效期(分钟)*/public static final Integer CAPTCHA_EXPIRATION = 2;/*** 令牌*/public static final String TOKEN = "token";/*** 令牌前缀*/public static final String TOKEN_PREFIX = "Bearer ";/*** 令牌前缀*/public static final String LOGIN_USER_KEY = "login_user_key";/*** 用户ID*/public static final String JWT_USERID = "userid";/*** 用户名称*///public static final String JWT_USERNAME = Claims.SUBJECT;/*** 用户头像*/public static final String JWT_AVATAR = "avatar";/*** 创建时间*/public static final String JWT_CREATED = "created";/*** 用户权限*/public static final String JWT_AUTHORITIES = "authorities";/*** 资源映射路径 前缀*/public static final String RESOURCE_PREFIX = "/profile";
}

2.9 base64 编码工具

package com.ruoyi.common.utils.sign;/*** Base64工具类** @author ruoyi*/
public final class Base64 {static private final int BASELENGTH = 128;static private final int LOOKUPLENGTH = 64;static private final int TWENTYFOURBITGROUP = 24;static private final int EIGHTBIT = 8;static private final int SIXTEENBIT = 16;static private final int FOURBYTE = 4;static private final int SIGN = -128;static private final char PAD = '=';static final private byte[] base64Alphabet = new byte[BASELENGTH];static final private char[] lookUpBase64Alphabet = new char[LOOKUPLENGTH];static {for (int i = 0; i < BASELENGTH; ++i) {base64Alphabet[i] = -1;}for (int i = 'Z'; i >= 'A'; i--) {base64Alphabet[i] = (byte) (i - 'A');}for (int i = 'z'; i >= 'a'; i--) {base64Alphabet[i] = (byte) (i - 'a' + 26);}for (int i = '9'; i >= '0'; i--) {base64Alphabet[i] = (byte) (i - '0' + 52);}base64Alphabet['+'] = 62;base64Alphabet['/'] = 63;for (int i = 0; i <= 25; i++) {lookUpBase64Alphabet[i] = (char) ('A' + i);}for (int i = 26, j = 0; i <= 51; i++, j++) {lookUpBase64Alphabet[i] = (char) ('a' + j);}for (int i = 52, j = 0; i <= 61; i++, j++) {lookUpBase64Alphabet[i] = (char) ('0' + j);}lookUpBase64Alphabet[62] = (char) '+';lookUpBase64Alphabet[63] = (char) '/';}private static boolean isWhiteSpace(char octect) {return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9);}private static boolean isPad(char octect) {return (octect == PAD);}private static boolean isData(char octect) {return (octect < BASELENGTH && base64Alphabet[octect] != -1);}/*** Encodes hex octects into Base64** @param binaryData Array containing binaryData* @return Encoded Base64 array*/public static String encode(byte[] binaryData) {if (binaryData == null) {return null;}int lengthDataBits = binaryData.length * EIGHTBIT;if (lengthDataBits == 0) {return "";}int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP;int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP;int numberQuartet = fewerThan24bits != 0 ? numberTriplets + 1 : numberTriplets;char encodedData[] = null;encodedData = new char[numberQuartet * 4];byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0;int encodedIndex = 0;int dataIndex = 0;for (int i = 0; i < numberTriplets; i++) {b1 = binaryData[dataIndex++];b2 = binaryData[dataIndex++];b3 = binaryData[dataIndex++];l = (byte) (b2 & 0x0f);k = (byte) (b1 & 0x03);byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6) : (byte) ((b3) >> 6 ^ 0xfc);encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)];encodedData[encodedIndex++] = lookUpBase64Alphabet[(l << 2) | val3];encodedData[encodedIndex++] = lookUpBase64Alphabet[b3 & 0x3f];}// form integral number of 6-bit groupsif (fewerThan24bits == EIGHTBIT) {b1 = binaryData[dataIndex];k = (byte) (b1 & 0x03);byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];encodedData[encodedIndex++] = lookUpBase64Alphabet[k << 4];encodedData[encodedIndex++] = PAD;encodedData[encodedIndex++] = PAD;} else if (fewerThan24bits == SIXTEENBIT) {b1 = binaryData[dataIndex];b2 = binaryData[dataIndex + 1];l = (byte) (b2 & 0x0f);k = (byte) (b1 & 0x03);byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)];encodedData[encodedIndex++] = lookUpBase64Alphabet[l << 2];encodedData[encodedIndex++] = PAD;}return new String(encodedData);}/*** Decodes Base64 data into octects** @param encoded string containing Base64 data* @return Array containind decoded data.*/public static byte[] decode(String encoded) {if (encoded == null) {return null;}char[] base64Data = encoded.toCharArray();// remove white spacesint len = removeWhiteSpace(base64Data);if (len % FOURBYTE != 0) {return null;// should be divisible by four}int numberQuadruple = (len / FOURBYTE);if (numberQuadruple == 0) {return new byte[0];}byte decodedData[] = null;byte b1 = 0, b2 = 0, b3 = 0, b4 = 0;char d1 = 0, d2 = 0, d3 = 0, d4 = 0;int i = 0;int encodedIndex = 0;int dataIndex = 0;decodedData = new byte[(numberQuadruple) * 3];for (; i < numberQuadruple - 1; i++) {if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++]))|| !isData((d3 = base64Data[dataIndex++])) || !isData((d4 = base64Data[dataIndex++]))) {return null;} // if found "no data" just return nullb1 = base64Alphabet[d1];b2 = base64Alphabet[d2];b3 = base64Alphabet[d3];b4 = base64Alphabet[d4];decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);}if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++]))) {return null;// if found "no data" just return null}b1 = base64Alphabet[d1];b2 = base64Alphabet[d2];d3 = base64Data[dataIndex++];d4 = base64Data[dataIndex++];if (!isData((d3)) || !isData((d4))) {// Check if they are PAD charactersif (isPad(d3) && isPad(d4)) {if ((b2 & 0xf) != 0)// last 4 bits should be zero{return null;}byte[] tmp = new byte[i * 3 + 1];System.arraycopy(decodedData, 0, tmp, 0, i * 3);tmp[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);return tmp;} else if (!isPad(d3) && isPad(d4)) {b3 = base64Alphabet[d3];if ((b3 & 0x3) != 0)// last 2 bits should be zero{return null;}byte[] tmp = new byte[i * 3 + 2];System.arraycopy(decodedData, 0, tmp, 0, i * 3);tmp[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);tmp[encodedIndex] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));return tmp;} else {return null;}} else { // No PAD e.g 3cQlb3 = base64Alphabet[d3];b4 = base64Alphabet[d4];decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);}return decodedData;}/*** remove WhiteSpace from MIME containing encoded Base64 data.** @param data the byte array of base64 data (with WS)* @return the new length*/private static int removeWhiteSpace(char[] data) {if (data == null) {return 0;}// count characters that's not whitespaceint newSize = 0;int len = data.length;for (int i = 0; i < len; i++) {if (!isWhiteSpace(data[i])) {data[newSize++] = data[i];}}return newSize;}
}

3、生成验证码

编写Controller 处理验证码请求:

package com.ruoyi.project.common;/*** 验证码操作处理** @author ruoyi*/
@RestController
@CrossOrigin
public class CaptchaController {@Autowiredprivate RedisCache redisCache;/*** 生成验证码*/@GetMapping("/captcha/captchaImage")public AjaxResult getCode(HttpServletResponse response) throws IOException {// 生成随机字串String verifyCode = VerifyCodeUtils.generateVerifyCode(4);// 唯一标识String uuid = IdUtils.simpleUUID();String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid;redisCache.setCacheObject(verifyKey, verifyCode, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);// 生成图片int w = 111, h = 36;ByteArrayOutputStream stream = new ByteArrayOutputStream();VerifyCodeUtils.outputImage(w, h, stream, verifyCode);try {AjaxResult ajax = AjaxResult.success();ajax.put("uuid", uuid);ajax.put("img", Base64.encode(stream.toByteArray()));return ajax;} catch (Exception e) {e.printStackTrace();return AjaxResult.error(e.getMessage());} finally {stream.close();}}
}

4、测试

启动SpringBoot 项目,然后重启前台项目,看一下验证码是否生成?

5、总结

本章节看上去内容挺多,实际并不是很多,章节的中间部分有很多工具类, 如封装redis缓存工具类,字符串工具类, 生成UUID工具类

最主要的是思路

这里回顾一下:

①、新建项目,引入 springboot-web和test 模块

②、指定端口号和项目访问根路径

③、整合 redis(引入依赖、配置reids,Redis配置类-为容器中注入redisTemplate),并封装redis常用操作

④、定义统一的AjaxResult返回类,以及相应状态码

⑤、封装 UUID、生成UUID、生成图片的工具类

⑥、编写Controller, 处理获取验证码请求!

 

查看全文
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

相关文章

  1. [java] 图片与base64之间的互相转换

    这篇文章实现的功能是,本地或者线上的图片转换成base64和base64转换成图片。好了不多说了,直接上代码!import java.io.ByteArrayOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream;…...

    2024/4/17 7:20:30
  2. 创业兵法:商业模式是创业之本

    2.1.2、商业模式创业路上总是布满了各式各样的困难,而其中最大的困难就是确立合适的商业模式。 在之前我们做了详细的市场分析之后,进入怎样的市场,怎样盈利是我们接下来要做的很重要的一件事。这也就是我们即将要提到的商业模式。 在切入市场之前,虽然前文我们提到过对于市…...

    2024/4/17 7:20:30
  3. 系统学习机器学习之神经网络(九) --Hopfield网络

    转自:http://blog.csdn.net/lg1259156776/article/details/47323889 一、前言 经过一段时间的积累,对于神经网络,已经基本掌握了感知器、BP算法及其改进、AdaLine等最为简单和基础的前馈型神经网络知识,下面开启的是基于反馈型的神经网络Hopfiled神经网络。前馈型神经网络通…...

    2024/4/18 23:44:15
  4. ContentProvider中gettype() 和MIME类型的理解

    转载处:http://blog.csdn.net/fangxinglian/article/details/22981277程序入口点 类似于win32程序里的WinMain函数,Android自然也有它的程序入口点。它通过在AndroidManifest.xml文件中配置来指明,可以看到名为NotesList的activity节点下有这样一个intent-filter,其action为…...

    2024/4/18 5:48:44
  5. 若依启动springboot项目报错{已解决}

    启动springboot项目报错,我使用的是若依的RuoYi-fast开源框架里面的自动生成代码功能生成的代码,生成完毕我放入项目中启动报错 16:10:41.046 [restartedMain] INFO c.r.RuoYiApplication - [logStarting,50] - Starting RuoYiApplication on DUXIU with PID 12772 (F:\zhgd…...

    2024/4/19 11:46:41
  6. Android原生模拟表单提交上传多图+PHP接收表单数据和多图存储

    转载请注明出处:http://blog.csdn.net/iwanghang/article/details/65630703觉得博文有用,请点赞,请评论,请关注,谢谢!~最近项目中实现多图提交,尝试了base64,16进制 异步上传多图。又尝试了一下Android模拟表单提交,并且把最近学习的TP5用上,写了一个接收多图的接口,…...

    2024/4/17 7:21:00
  7. 计算机三级网络技术知识点

    第一章:网络系统统结构与设计的基本原则计算机网络按地理范围划分为局域网,城域网,广域网;局域网提供高数据传输速率 10mbps-10gbps,低误码率的高质量传输环境局域网按介质访问控制方法角度分为共享介质式局域网和交换式局域网[SD1] 局域网按传输介质类型角度分为有线介质局…...

    2024/4/20 8:28:07
  8. 产品经理如何写出一看就想约的简历

    2010年工商管理专业毕业后怀揣着一份商业计划书(农业方面)前往北京找投资,兜兜转转了4个月后折戟而归;之后进入中兴通讯旗下子公司做开放平台运营(类似于豌豆荚和应用宝),1年后进入电信天翼空间做解决方案;3年后离开电信加入创业公司做婚恋产业方面的创业(商业模式有点…...

    2024/4/4 22:38:16
  9. 将链接转成base64格式生成二维码和把页面生成图片

    将链接转成base64格式function getUrlBase64 (url, etx, callback) {var canvas = document.createElement(canvas)var ctx = canvas.getContext(2d)var img = new Image()img.src = urlimg.crossOrigin = Anonymousimg.onload = function () {canvas.width = img.widthcanvas.…...

    2024/4/28 10:54:43
  10. Base64与File之间的相互转化

    问题:最近遇到一个上传文件的问题,前端使用了另一种传值,就是Base64字符串传给后台 ,一开始没有对其进行解码操作,存入数据库时就超长了,今天这里提供一种base64和file之间相互转化的工具类,以便日后参考/**** @param path* @return String* @description 将文件转base6…...

    2024/4/20 4:57:02
  11. 创业基础(第7章 创业计划) 来自高校:全国大学生创新创业实践联盟 分类:创新创业 学习规则:按序学习

    7.1:(单选) 以下关于创业计划的说法,正确的是(D)A. 创业计划是一份全面说明创业构想以及如何实施创业构想的文件 B. 创业计划描述所要创立的企业是什么以及将成为什么的故事 C. 如果把创业比作一个旅程,一个不熟悉且充满不确定性的旅程,那么创业计划更像一个行动路线图…...

    2024/4/17 7:21:36
  12. Intellij IDEA中修改Maven项目的项目名称

    大家好,用maven来管理我们的项目是我们现在的首选.那么如何给一个maven项目改名?要注意哪些细节,我们来一起开一下。一.终极目标我们现在要将原项目名:ruoyi 重命名成新项目名:website二.操作流程首先我们找到项目在磁盘中的位置,将它重命名为 website接下来,我们把项目导…...

    2024/4/17 7:21:06
  13. 网络的需求分析和规划

    1、计算模式专用服务器模式 客户机/服务器(Client/Server)模式 浏览器/服务器(Browser/Server)模式...

    2024/5/8 12:14:52
  14. centos打包项目时出现的问题及解决方法

    使用npm run build:prod报错 npm ERR! code ELIFECYCLE npm ERR! errno 1 npm ERR! ruoyi@2.3.0 build:prod: `vue-cli-service build` npm ERR! Exit status 1 npm ERR! npm ERR! Failed at the ruoyi@2.3.0 build:prod script. npm ERR! This is probably not a problem wit…...

    2024/5/8 11:29:52
  15. 大数据学习一般都需要学习哪些知识

    基础阶段:Linux、Docker、KVM、MySQL基础、Oracle基础、MongoDB、redis。hadoop mapreduce hdfs yarn:hadoop:推Hadoop 概念、版本、历史,HDFS工作原理,YARN介绍及组件介绍。荐一个大数据学习群 119599574每天晚上20:10都有一节【免费的】大数据直播课程,专注大数据分析方…...

    2024/4/17 7:21:54
  16. Android拍照选择图片上传服务器自定义控件

    做android项目的时候总免不了遇到图片上传功能,虽然就是调用android系统的拍照和相册选择功能,但是总面部了把一大推代码写在activity里,看上去一大推代码头都昏了。不如把这些功能都集成一个控件,以后遇到图片上传功能也不用那么麻烦了。好啦,下面开始上效果图。</pre…...

    2024/4/19 15:52:03
  17. 干货——BRD(商业需求文档)模板

    项目名称商业需求文档文件状态:[√] 草稿[ ] 正式发布[ ] 正在修改文件标识:Company-Project-RD-UR当前版本:X.Y作 者:人人都是产品经理、起点学院完成日期:Year-Month-Day1. 摘要1.1 文档目的阐述项目的商业价值,该产品被开发出来的重要性。1.2 参考文档 提示:列出…...

    2024/4/17 7:20:36
  18. 撰写网站规划书

    撰写一个网站的规划书,内容包括前期调研分析;确定网站目的及功能定位;拟出网站技术解决方案;对网站内容进行规划,网页效果进行大致设计;列出网站维护、测试、网站发布与推广方案等 1.基本知识与技能 1.1网站的工作原理 1.1.1静态网页的工作原理1.1.2动态网页的工作原理1.…...

    2024/4/17 7:21:36
  19. 若依框架部署到idea

    RuoYi 是一个 Java EE 企业级快速开发平台,基于经典技术组合(Spring Boot、Apache Shiro、MyBatis、Thymeleaf、Bootstrap),内置模块如:部门管理、角色用户、菜单及按钮授权、数据权限、系统参数、日志管理、通知公告等。在线定时任务配置;支持集群,支持多数据源。主要特…...

    2024/4/19 10:07:18
  20. Android MediaStore检索视频并播放

    该文章是为了检索手机上sd卡中的视频,然后将检索出来的相应视频的缩略图,名称等视频信息显示在ListView上。点击每个item后播放相应的视频。 源代码:布局文件: activity_main: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xm…...

    2024/4/18 13:23:54

最新文章

  1. citylava:城市场景中VLMs的有效微调

    citylava:城市场景中VLMs的有效微调 摘要IntroductionRelated WorkVision-Language ModelsVLMs in Driving Methodology CityLLaVA: Efficient Fine-Tuning for VLMs in City Scenario 摘要 在城市广阔且动态的场景中&#xff0c;交通安全描述与分析在从保险检查到事故预防的各…...

    2024/5/8 14:13:09
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/5/7 10:36:02
  3. 使用阿里云试用Elasticsearch学习:3.5 处理人类语言——停用词: 性能与精度

    从早期的信息检索到如今&#xff0c; 我们已习惯于磁盘空间和内存被限制为很小一部分&#xff0c;所以 必须使你的索引尽可能小。 每个字节都意味着巨大的性能提升。 (查看 将单词还原为词根 ) 词干提取的重要性不仅是因为它让搜索的内容更广泛、让检索的能力更深入&#xff0c…...

    2024/5/4 1:29:52
  4. 图像处理相关知识 —— 椒盐噪声

    椒盐噪声是一种常见的图像噪声类型&#xff0c;它会在图像中随机地添加黑色&#xff08;椒&#xff09;和白色&#xff08;盐&#xff09;的像素点&#xff0c;使图像的质量降低。这种噪声模拟了在图像传感器中可能遇到的问题&#xff0c;例如损坏的像素或传输过程中的干扰。 椒…...

    2024/5/5 8:37:08
  5. 产品推荐 | 中科亿海微推出亿迅®A8000金融FPGA加速卡

    01、产品概述 亿迅A8000金融加速卡&#xff0c;是中科亿海微联合金融证券领域的战略合作伙伴北京睿智融科&#xff0c;将可编程逻辑芯片与金融行业深度结合&#xff0c;通过可编程逻辑芯片对交易行情加速解码&#xff0c;实现低至纳秒级的解码引擎&#xff0c;端到端的处理时延…...

    2024/5/7 18:18:40
  6. 【外汇早评】美通胀数据走低,美元调整

    原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...

    2024/5/8 6:01:22
  7. 【原油贵金属周评】原油多头拥挤,价格调整

    原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...

    2024/5/7 9:45:25
  8. 【外汇周评】靓丽非农不及疲软通胀影响

    原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...

    2024/5/4 23:54:56
  9. 【原油贵金属早评】库存继续增加,油价收跌

    原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...

    2024/5/7 14:25:14
  10. 【外汇早评】日本央行会议纪要不改日元强势

    原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...

    2024/5/4 23:54:56
  11. 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响

    原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...

    2024/5/4 23:55:05
  12. 【外汇早评】美欲与伊朗重谈协议

    原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...

    2024/5/4 23:54:56
  13. 【原油贵金属早评】波动率飙升,市场情绪动荡

    原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...

    2024/5/7 11:36:39
  14. 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试

    原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...

    2024/5/4 23:54:56
  15. 【原油贵金属早评】市场情绪继续恶化,黄金上破

    原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...

    2024/5/6 1:40:42
  16. 【外汇早评】美伊僵持,风险情绪继续升温

    原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...

    2024/5/4 23:54:56
  17. 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势

    原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...

    2024/5/4 23:55:17
  18. 氧生福地 玩美北湖(上)——为时光守候两千年

    原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...

    2024/5/7 9:26:26
  19. 氧生福地 玩美北湖(中)——永春梯田里的美与鲜

    原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...

    2024/5/4 23:54:56
  20. 氧生福地 玩美北湖(下)——奔跑吧骚年!

    原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...

    2024/5/4 23:55:06
  21. 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!

    原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...

    2024/5/5 8:13:33
  22. 「发现」铁皮石斛仙草之神奇功效用于医用面膜

    原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...

    2024/5/4 23:55:16
  23. 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者

    原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...

    2024/5/4 23:54:58
  24. 广州械字号面膜生产厂家OEM/ODM4项须知!

    原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...

    2024/5/6 21:42:42
  25. 械字号医用眼膜缓解用眼过度到底有无作用?

    原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...

    2024/5/4 23:54:56
  26. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  27. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  28. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  29. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  30. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  31. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  32. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  33. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  34. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  35. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  36. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  37. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  38. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  39. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  40. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  41. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  42. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  43. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  44. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  45. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57