首页
资源库
留言板
站点统计
Search
1
[Java] @Data 注解 代码变得简洁
205 阅读
2
[Vue] Vue 使用ElementUI组件
162 阅读
3
[Java] 安装JDK8
131 阅读
4
[Java] 发送消息
122 阅读
5
[C语言] 游戏贪吃蛇
108 阅读
Tools
编程
C/C++
Java
mySQL
python
PHP
Vue
嵌入式系统编程
HTML
数据结构
TypeScript
登录
Search
标签搜索
Java
SpringBoot
数据结构
C/C++
mysql
Vue
tools
redis
游戏
TomCat
linux
arm
嵌入式系统
Mqtt
PHP
maven
图床
github
IDEA
jar
星如雨
累计撰写
48
篇文章
累计收到
2
条评论
首页
栏目
Tools
编程
C/C++
Java
mySQL
python
PHP
Vue
嵌入式系统编程
HTML
数据结构
TypeScript
页面
资源库
留言板
站点统计
搜索到
17
篇与
的结果
2023-03-14
[java] Base64 utils文件
在项目启动目录创建 utils -> Base64.java/** * Base64工具类 * */ 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 groups if (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 spaces int 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 null b1 = 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 characters if (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 3cQl 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); } 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 whitespace int newSize = 0; int len = data.length; for (int i = 0; i < len; i++) { if (!isWhiteSpace(data[i])) { data[newSize++] = data[i]; } } return newSize; } }
2023年03月14日
14 阅读
0 评论
0 点赞
2023-03-14
[spring boot] spring boot 中redis 工具类
在项目启动目录创建 utils -> RedisCache.javaimport java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.BoundSetOperations; import org.springframework.data.redis.core.HashOperations; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.ValueOperations; import org.springframework.stereotype.Component; /** * spring redis 工具类 **/ @SuppressWarnings(value = {"unchecked", "rawtypes"}) @Component public class RedisCache { @Autowired public RedisTemplate redisTemplate; /** * 缓存基本的对象,Integer、String、实体类等 * * @param key 缓存的键值 * @param value 缓存的值 */ public <T> void setCache(final String key, final T value) { redisTemplate.opsForValue().set(key, value); } /** * 缓存基本的对象,Integer、String、实体类等 * * @param key 缓存的键值 * @param value 缓存的值 * @param timeout 时间 * @param timeUnit 时间颗粒度 */ public <T> void setCache(final String key, final T value, final Integer timeout, final TimeUnit timeUnit) { redisTemplate.opsForValue().set(key, value, timeout, timeUnit); } /** * 设置有效时间 * * @param key Redis键 * @param timeout 超时时间 * @return true=设置成功;false=设置失败 */ public boolean expire(final String key, final long timeout) { return expire(key, timeout, TimeUnit.SECONDS); } /** * 设置有效时间 * * @param key Redis键 * @param timeout 超时时间 * @param unit 时间单位 * @return true=设置成功;false=设置失败 */ public boolean expire(final String key, final long timeout, final TimeUnit unit) { return redisTemplate.expire(key, timeout, unit); } /** * 获取有效时间 * * @param key Redis键 * @return 有效时间 */ public long getExpire(final String key) { return redisTemplate.getExpire(key); } /** * 判断 key是否存在 * * @param key 键 * @return true 存在 false不存在 */ public Boolean hasKey(String key) { return redisTemplate.hasKey(key); } /** * 获得缓存的基本对象。 * * @param key 缓存键值 * @return 缓存键值对应的数据 */ public <T> T getCache(final String key) { ValueOperations<String, T> operation = redisTemplate.opsForValue(); return operation.get(key); } /** * 删除单个对象 * * @param key */ public boolean delete(final String key) { return redisTemplate.delete(key); } /** * 删除集合对象 * * @param collection 多个对象 * @return */ public boolean delete(final Collection collection) { return redisTemplate.delete(collection) > 0; } /** * 缓存List数据 * * @param key 缓存的键值 * @param dataList 待缓存的List数据 * @return 缓存的对象 */ public <T> long setCacheList(final String key, final List<T> dataList) { Long count = redisTemplate.opsForList().rightPushAll(key, dataList); return count == null ? 0 : count; } /** * 获得缓存的list对象 * * @param key 缓存的键值 * @return 缓存键值对应的数据 */ public <T> List<T> getCacheList(final String key) { return redisTemplate.opsForList().range(key, 0, -1); } /** * 缓存Set * * @param key 缓存键值 * @param dataSet 缓存的数据 * @return 缓存数据的对象 */ public <T> BoundSetOperations<String, T> setCacheSet(final String key, final 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(final String key) { return redisTemplate.opsForSet().members(key); } /** * 缓存Map * * @param key * @param dataMap */ public <T> void setCacheMap(final String key, final Map<String, T> dataMap) { if (dataMap != null) { redisTemplate.opsForHash().putAll(key, dataMap); } } /** * 获得缓存的Map * * @param key * @return */ public <T> Map<String, T> getCacheMap(final String key) { return redisTemplate.opsForHash().entries(key); } /** * 往Hash中存入数据 * * @param key Redis键 * @param hKey Hash键 * @param value 值 */ public <T> void setCacheMapValue(final String key, final String hKey, final T value) { redisTemplate.opsForHash().put(key, hKey, value); } /** * 获取Hash中的数据 * * @param key Redis键 * @param hKey Hash键 * @return Hash中的对象 */ public <T> T getCacheMapValue(final String key, final String hKey) { HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash(); return opsForHash.get(key, hKey); } /** * 获取多个Hash中的数据 * * @param key Redis键 * @param hKeys Hash键集合 * @return Hash对象集合 */ public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys) { return redisTemplate.opsForHash().multiGet(key, hKeys); } /** * 删除Hash中的某条数据 * * @param key Redis键 * @param hKey Hash键 * @return 是否成功 */ public boolean deleteCacheMapValue(final String key, final String hKey) { return redisTemplate.opsForHash().delete(key, hKey) > 0; } /** * 获得缓存的基本对象列表 * * @param pattern 字符串前缀 * @return 对象列表 */ public Collection<String> keys(final String pattern) { return redisTemplate.keys(pattern); } }
2023年03月14日
36 阅读
0 评论
0 点赞
2023-02-14
[Java] mybatis-plus 联表查询
前言作为mybatis的增强工具,mybatis-plus的出现极大的简化了开发中的数据库操作,但是长久以来,它的联表查询能力一直被大家所诟病。一旦遇到left join或right join的左右连接,手写上一大段的sql语句。mybatis-plus-join 介绍MyBatis-Plus-Join (简称 MPJ)是一个 MyBatis-Plus 的增强工具,在 MyBatis-Plus 的基础上只做增强不做改变,为简化开发、提高效率而生。特性无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑无感引入, 支持MP风格的查询, 您会MP就会MPJ, 无需额外的学习成本兼容MP的别名、逻辑删除、枚举列、TypeHandle列等特性支持注解形式一对一、一对多和连表查询形式的一对一和一对多代码托管github.com | gitee.com使用官方文档
2023年02月14日
81 阅读
0 评论
0 点赞
2022-05-20
[Java] SpringBoot 异步任务
SpringBoot 异步任务开启异步任务启动类开启异步任务异步服务业务@Service public class TaskService { /** * 异步服务,无返回值 */ @Async public void sendMsg() throws Exception { System.out.println("任务服务消息开启..."); long sTime = System.currentTimeMillis(); System.out.println("开始时间:" + sTime); Thread.sleep(5000); long eTime = System.currentTimeMillis(); System.out.println("结束时间:" + eTime); System.out.println("总用时:" + (eTime - sTime)); } /** * 异步服务,有返回值 */ @Async public Future<Integer> TaskA() throws InterruptedException { System.out.println("TaskA 开始执行"); long sTime = System.currentTimeMillis(); System.out.println("TaskA 开始时间:" + sTime); Thread.sleep(5000); Integer res = Math.toIntExact(Math.round(Math.random() * 1000000)); long eTime = System.currentTimeMillis(); System.out.println("TaskA 结束时间:" + eTime); System.out.println("TaskA 总用时:" + (eTime - sTime)); return new AsyncResult<Integer>(res); } /** * 异步服务,有返回值 */ @Async public Future<Integer> TaskB() throws InterruptedException { System.out.println("TaskB 开始执行"); long sTime = System.currentTimeMillis(); System.out.println("TaskB 开始时间:" + sTime); Thread.sleep(5000); Integer res = Math.toIntExact(Math.round(Math.random() * 1000000)); long eTime = System.currentTimeMillis(); System.out.println("TaskB 结束时间:" + eTime); System.out.println("TaskB 总用时:" + (eTime - sTime)); return new AsyncResult<Integer>(res); } }不要使用 测试单元运行,会出现异步业务没有执行结束,项目就停止运行了Controller 类@RestController public class AsyncTaskController { @Autowired TaskService taskService; @GetMapping("/voidReturnTask") public String voidReturnTask() throws Exception { long sTime = System.currentTimeMillis(); taskService.sendMsg(); long eTime = System.currentTimeMillis(); System.out.println("voidReturnTask run Time:" + (eTime - sTime) + "s"); return "voidReturnTask success"; } @GetMapping("/hasReturnTask") public String hasReturnTask() throws Exception { long sTime = System.currentTimeMillis(); Future<Integer> taskA = taskService.TaskA(); Future<Integer> taskB = taskService.TaskB(); int i = taskA.get() + taskB.get(); System.out.println("两个任务结果:" + i); long eTime = System.currentTimeMillis(); System.out.println("hasReturnTask run Time:" + (eTime - sTime) + "s"); return "hasReturnTask success"; } }运行在浏览器分别访问localhost:8088/voidReturnTasklocalhost:8088/hasReturnTask
2022年05月20日
64 阅读
0 评论
0 点赞
2022-05-13
[Java] Springboot 使用 RabbitMQ 消息服务
安装 RabittMQ 服务由于 RabittMQ 基于 erlang 语言,因此在安装的时需要先安装erlang下载 erlang下载链接:https://www.erlang.org/downloads 这个可能有点慢,毕竟是外国网站,要是不想要最新版选择下面百度网盘下载{cloud title="erlang下载" type="bd" url="https://pan.baidu.com/s/1c848j2odvZxwHvplJVsJ8A" password="b21g"/}下载后双击.exe 文件安装即可,安装结束配置一下环境变量,检查环境变量是否配置成功下载 RabbitMQ下载链接:https://www.rabbitmq.com/download.html 这个也很慢,没办法,还是百度网盘吧{cloud title="RabbitMQ" type="bd" url="https://pan.baidu.com/s/1sbaNeA3ofyCVncv-MxaKeQ" password="zgkj"/}双击即可安装(注意安装目录中尽量不要有空格),在安装的过程发现安装好之后就自动启动了进入安装目录下的 sbin 目录 打开命令提示提示符窗口# 安装rabbitmq插件 rabbitmq-plugins enable rabbitmq_managemen # 若出现错误,需要重启服务,正常请忽略 Rabbitmq-service stop rabbitmq-service若停止服务失败,错误代码5。说明权限不够,系统登录的是普通用户,需要管理员的权限执行该命令。用管理员打开cmd,之后执行rabbitmq-service stop rabbitmq-service remove rabbitmq-service install rabbitmq-service start rabbitmq-plugins enable rabbitmq_management插件安装完成在浏览器中输入:http://localhost:15672 查看输入用户名:guest,密码:guestSpringBoot 使用Rabbit 服务使用依赖这个依赖是SpringBoot 自己集成好的,引入直接用就可以了<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency>配置RabbitMQspring: rabbitmq: host: 127.0.0.1 port: 5672 username: guest password: guest virtual-host: /API 方式整合 RabbitMQ@RunWith(SpringRunner.class) @SpringBootTest public class RabbitMQTest { // API 方式 @Autowired AmqpAdmin amqpAdmin; @Test public void amqpAdminTest() { // 定义信息 String ExangeName = "fanout_exchange"; List<String> MsgQueues = new LinkedList<>(); MsgQueues.add("fanout_queue_email"); MsgQueues.add("fanout_queue_sms"); // 定义 fanout 类型交换器,(用户发送数据经交换机分发,进入不同的消息队列) amqpAdmin.declareExchange(new FanoutExchange(ExangeName)); // 定义两个消息队列,用于接收交换机分发的数据 for (String queue : MsgQueues) { amqpAdmin.declareQueue(new Queue(queue)); } // 将消息队列绑定到交换机中 for (String queue : MsgQueues) { amqpAdmin.declareBinding(new Binding(queue, Binding.DestinationType.QUEUE, ExangeName, "", null)); } } }运行一下,打开浏览器访问可视化窗口,增加了一个交换器,也会增加两个消息队列创建一个发送的数据类public class RabbitUser { private Integer id; private String username; public RabbitUser() {} public RabbitUser(Integer id, String username) { this.id = id; this.username = username; } // 省去get/set 和 toString方法 }测试消息@Autowired private RabbitTemplate rabbitTemplate; @Test public void publishSubscribe() { // 发送消息 RabbitUser rabbitUser = new RabbitUser(1, "admin"); // rabbitmq 发送字符串或者 bite 类型 rabbitTemplate.convertAndSend("fanout_exchange", "", rabbitUser.toString()); }自定义类型消息类型,避免乱码@Configuration public class RabbitMQConfig { @Bean public MessageConverter messageConverter() { return new Jackson2JsonMessageConverter(); } }运行获取发送的消息信息@Service public class RabbitMQService { // 接收邮件 @RabbitListener(queues = "fanout_queue_email") public void psubConsumerEmail(Message message) { System.out.println("MsgAllInfo:" + message); } // 接收短信 @RabbitListener(queues = "fanout_queue_sms") public void psubConsumerSms(Message message) { String s = new String(message.getBody()); System.out.println("Sms: " + s); } }运行控制台打印结果可视化面板结果基于注解在RabbitConfig 类中添加配置@Bean public Exchange fanout_exchange() { return ExchangeBuilder.fanoutExchange("fanout_exchange").build(); } @Bean public Queue fanout_queue_email() { return new Queue("fanout_queue_email"); } @Bean public Queue fanout_queue_sms() { return new Queue("fanout_queue_sms"); } @Bean public Binding bindingEmail() { return BindingBuilder.bind(fanout_queue_email()).to(fanout_exchange()).with("").noargs(); } @Bean public Binding bindingSms() { return BindingBuilder.bind(fanout_queue_sms()).to(fanout_exchange()).with("").noargs(); }接受处理方法@RabbitListener(bindings = @QueueBinding(value = @Queue("fanout_queue_email"), exchange = @Exchange(value = "fanout_exchange", type = "fanout"))) public void psubConsumerEmail(RabbitUser user) { System.out.println("Email:" + user); } @RabbitListener(bindings = @QueueBinding(value = @Queue("fanout_queue_sms"), exchange = @Exchange(value = "fanout_exchange", type = "fanout"))) public void psubConsumerSms(RabbitUser user) { System.out.println("Sms:" + user); }
2022年05月13日
86 阅读
0 评论
0 点赞
2022-05-12
[Java] Springboot 自定义登录页面
LoginController@Controller public class LoginController { // 设置 login页面为get方式传参 @GetMapping("/userLogin") public String login(Model model) { return "login/login"; } }login.html<div id="app"> <div style="width: 275px;margin: 130px auto;"> <h2>用户登录</h2> <el-form method="post" action="/userLogin"> <el-form-item> <el-input v-model="username" type="text" name="name" placeholder="用户名" clearable autofocus="true"></el-input> </el-form-item> <el-form-item> <el-input v-model="pwd" type="password" name="pwd" placeholder="密码" clearable show-password></el-input> </el-form-item> <input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}"> <el-form-item> <el-checkbox name="rememberme" v-model="rememberMe">记住密码</el-checkbox> </el-form-item> <el-form-item> <el-button native-type="submit" type="primary">登 录</el-button> <el-button type="primary" plain>注 册</el-button> </el-form-item> </el-form> </div> </div> <script src="https://fastly.jsdelivr.net/npm/vue@2.5.17/dist/vue.js"></script> <script src="https://unpkg.com/element-ui/lib/index.js"></script> <script> let vue = new Vue({ el: "#app", type : "module", data: function () { return { username: "", pwd: "", rememberMe: false } }, mounted: function () { }, }) </script>SecurityConfig@EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private DataSource dataSource; // UserDetailsService 安全认证 @Autowired private UserDetailsServiceImpl userDetailsService; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(); auth.userDetailsService(userDetailsService).passwordEncoder(encoder); } @Bean public JdbcTokenRepositoryImpl tokenRepository(){ JdbcTokenRepositoryImpl jr=new JdbcTokenRepositoryImpl(); jr.setDataSource(dataSource); return jr; } @Override protected void configure(HttpSecurity http) throws Exception { // 配置页面访问权限 /** * "/" 根目录 resources/template/index.html 权限为所有人均可访问 * "/detail/**" /detail 下面的所有目录或页面vip权限用户均可访问 * "/detail/common/**" /detail/common/** 下面的所有页面 common 权限用户均可访问 * anyRequest 所有的请求,必须通过身份认证 并且 开启用户登录机制 */ http.authorizeRequests() .antMatchers("/").permitAll() .antMatchers("/getUserBySession").permitAll() .antMatchers("/login/**").permitAll() .antMatchers("/detail/**").hasRole("vip") .antMatchers("/detail/common/**").hasRole("common") .anyRequest().authenticated().and().formLogin(); /** * 自定义用户登录控制 * 登录页面 /login * 需要参数为 name 用户名 pwd 用户密码 * 默认成功路径 / * 错误路径 /login */ http.formLogin() .loginPage("/userLogin").permitAll() .usernameParameter("name").passwordParameter("pwd") .defaultSuccessUrl("/") .failureUrl("/userLogin?res=error") .and().logout(); /** * 退出登录 */ http.logout() .logoutUrl("/userLogout") .logoutSuccessUrl("/userLogin"); } }
2022年05月12日
49 阅读
0 评论
0 点赞
2022-05-07
[Java] SpringBoot 用户安全访问
用户安全访问区分用户权限,不同的用户赋予不同的访问管理权限,使管理更高效SpringBoot中共有三种安全访问机制:内存安全认证jdbc安全认证UserDetailsService 安全认证使用的依赖<!-- 安全管理--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>数据库中一定要有三个数据库表:t_customer、t_authority、t_customer_authority分别是用户表,用户权限表,用户与用户权限对应表-- 用户表 DROP TABLE IF EXISTS `t_customer`; CREATE TABLE `t_customer` ( `id` INT(20) NOT NULL AUTO_INCREMENT, `username` VARCHAR(200) DEFAULT NULL, `password` VARCHAR(200) DEFAULT NULL, `valid` TINYINT(1) NOT NULL DEFAULT '1', PRIMARY KEY (`id`) ) ENGINE=INNODB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; -- 权限表 DROP TABLE IF EXISTS `t_authority`; CREATE TABLE `t_authority` ( `id` INT(20) NOT NULL AUTO_INCREMENT, `authority` VARCHAR(20) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=INNODB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; -- 用户与权限对应关系 DROP TABLE IF EXISTS `t_customer_authority`; CREATE TABLE `t_customer_authority` ( `id` INT(20) NOT NULL AUTO_INCREMENT, `customer_id` INT(20) DEFAULT NULL, `authority_id` INT(20) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=INNODB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; -- 插入一些数据 INSERT INTO `t_customer` VALUES ('1', 'admin', '$2a$10$5ooQI8dir8jv0/gCa1Six.GpzAdIPf6pMqdminZ/3ijYzivCyPlfK', '1'); INSERT INTO `t_customer` VALUES ('2', 'shitou', '$2a$10$5ooQI8dir8jv0/gCa1Six.GpzAdIPf6pMqdminZ/3ijYzivCyPlfK', '1'); INSERT INTO `t_customer` VALUES ('3', '李四', '$2a$10$5ooQI8dir8jv0/gCa1Six.GpzAdIPf6pMqdminZ/3ijYzivCyPlfK', '1'); INSERT INTO `t_authority` VALUES ('1', 'common'); INSERT INTO `t_authority` VALUES ('2', 'vip'); INSERT INTO `t_customer_authority` VALUES ('1', '1', '1'); INSERT INTO `t_customer_authority` VALUES ('2', '2', '2');创建实体类客户实体类@Data @Entity(name = "t_customer") public class Customer { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; /** * 客户用户名 */ private String username; /** * 客户密码 */ private String password; }权限实体类@Entity(name = "t_authority") @Data public class Authority { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; private String authority ; }创建Repository 接口 管理业务语句public interface CustomerRepository extends JpaRepository<Customer, Integer> { @Query(value = "select id from t_customer",nativeQuery = true) public List<Customer> getAllUser(); public Customer findByUsername(String username); public boolean existsCustomerByIdAndUsername(Integer id,String username); public List<Customer> getCustomerByIdAndUsername(Integer id,String username); } public interface AuthorityRepository extends JpaRepository<Authority, Integer> { @Query(value = "select a.* from t_customer c,t_authority a,t_customer_authority ca where ca.customer_id=c.id and ca.authority_id=a.id and c.username =?1",nativeQuery = true) public List<Authority> findAuthoritiesByUsername(String username); }客户信息管理CustomerService@Service public class CustomerService { @Autowired private CustomerRepository customerRepository; @Autowired private AuthorityRepository authorityRepository; @Autowired private RedisTemplate redisTemplate; public Customer getCustomer(String username) { Customer customer = null; Object o = redisTemplate.opsForValue().get("customer_" + username); if (o != null) { customer = (Customer) o; } else { customer = customerRepository.findByUsername(username); if (customer != null) { redisTemplate.opsForValue().set("customer_" + username, customer); } } return customer; } public List<Authority> getCustomerAuthority(String username) { List<Authority> authorities = null; Object o = redisTemplate.opsForValue().get("authorities_" + username); if (o != null) { authorities = (List<Authority>) o; } else { authorities = authorityRepository.findAuthoritiesByUsername(username); if (authorities.size() > 0) { redisTemplate.opsForValue().set("authorities_" + username, authorities); } } return authorities; } }@EnableWebSecurity 开启安全模式内存安全管理模式@EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { // 内存认证 @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { // 加密方式 BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder(); // 写死的账号密码, // 用户名 shitou 密码 123456 权限 为 common // 用户名 李四 密码 123456 权限为 vip auth.inMemoryAuthentication().passwordEncoder(bCryptPasswordEncoder) .withUser("li").password(bCryptPasswordEncoder.encode("111111")).roles("common") .and().withUser("李四").password(bCryptPasswordEncoder.encode("222222")).roles("vip"); } }JDBC 数据库安全身份认证模式@EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private DataSource dataSource; // 数据库认证方式 @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(); // 查询用户的语句 String us = "select username,password,valid from t_customer where username=?"; // 查询 用户名以及用户权限的语句 String as = "select c.username,a.authority from t_customer c, t_authority a, t_customer_authority ca " + "where ca.customer_id=c.id and ca.authority_id=a.id and c.username=?"; // 设置 用户校验规则为 encoder 数据库源为 dataSource 设置查询用户语句,查询权限语句 auth.jdbcAuthentication() .passwordEncoder(encoder) .dataSource(dataSource) .usersByUsernameQuery(us) .authoritiesByUsernameQuery(as); } }UserDetailService 数据库安全身份认证模式@EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { // UserDetailsService 安全认证 @Autowired private UserDetailsServiceImpl userDetailsService; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { System.out.println("UserDetailService 身份验证"); BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(); auth.userDetailsService(userDetailsService).passwordEncoder(encoder); } }浏览器访问本地地址即可,自动跳转到login页面这里的login页面是身份安全认证自己默认的,并不是自己创建的使用@Controller 跳转的login.html页面
2022年05月07日
68 阅读
0 评论
0 点赞
2022-05-07
[Java] @Data 注解 代码变得简洁
使用的依赖<!-- lombok--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency>如果我们有一个 Person 类代码里面一般会写成这样public class Person { private String id; private String name; private List<String> hobbies; private String[] family; @Override public String toString() { return "Person{" + "id='" + id + '\'' + ", name='" + name + '\'' + ", hobbies=" + hobbies + ", family=" + Arrays.toString(family) + '}'; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public List<String> getHobbies() { return hobbies; } public void setHobbies(List<String> hobbies) { this.hobbies = hobbies; } public String[] getFamily() { return family; } public void setFamily(String[] family) { this.family = family; } }里面有太多的set和get方法,在代码阅读的时候就不太友好,为了方便我们,可以使用 @Data 默认就会有get、set、toString方法@Data public class Person { private String id; private String name; private List<String> hobbies; private String[] family; }虽然在使用个的时候IDEA 依然会报错说使用的类没有set或get方法,但仍然可以运行,不会抛出异常
2022年05月07日
205 阅读
0 评论
1 点赞
2022-04-24
[Java] SpringBoot redis 注解缓存数据库数据
在数据库中执行创建数据库以创建一个评论表为例创建数据库DROP DATABASE IF EXISTS `springbootdata`; CREATE DATABASE `springbootdata`;创建表CREATE TABLE `t_comment` ( `id` int(20) NOT NULL AUTO_INCREMENT COMMENT '评论id', `content` longtext COMMENT '评论内容', `author` varchar(200) DEFAULT NULL COMMENT '评论作者', `a_id` int(20) DEFAULT NULL COMMENT '关联的文章id', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;添加部分数据INSERT INTO `t_comment` VALUES ('1', '1', '1', '1'), ('2', '赞一个', 'tom', '1'), ('3', '很详细', 'kitty', '1'), ('4', '很好,非常详细', '张三', '1'), ('5', '很不错', '张杨', '2');SpringBoot 部分引入依赖 <dependencies> <!-- spring-boot-starter-web--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- 核心:自动配置的支持、日志、yaml解析等--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <!-- 阿里巴巴解析json依赖--> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.47</version> </dependency> <!-- httpclient请求依赖--> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> </dependency> <!-- 爬虫+解析--> <dependency> <groupId>org.jsoup</groupId> <artifactId>jsoup</artifactId> <version>1.10.3</version> </dependency> <!-- junit--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <!-- SpringBoot test--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- mysql--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.27</version> <scope>runtime</scope> </dependency> <!-- myBatis --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.2.2</version> </dependency> <!-- alibaba 数据库池 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.22</version> </dependency> <!-- jpa 依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <!-- 热部署--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency> <!-- lombok--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <!-- 可视化接口API--> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.4.0</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.4.0</version> </dependency> <!-- thymeleaf 模板--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <!-- 文件下载依赖--> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.6</version> </dependency> <!-- Tomcat依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <scope>provided</scope> </dependency> <!-- Redis依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> </dependencies>配置redis# 配置MySQL数据库 数据库地址 用户名 密码 spring.datasource.url=jdbc:mysql://localhost:3306/springbootdata?serverTimezone=UTC spring.datasource.username=root spring.datasource.password=123456 # 显示 jpa sql 语句 执行jpa 的时候会在控制台打印jpa 语句 spring.jpa.show-sql=true # 配置第三方数据库源 druid spring.datasource.type=com.alibaba.druid.pool.DruidDataSource spring.datasource.druid.initial-size=20 spring.datasource.druid.min-idle=10 spring.datasource.druid.max-active=100 # 配置 Redis spring.redis.host=127.0.0.1 spring.redis.port=6379 spring.redis.password= 创建 Discuss 实例Discuss// 使数据库数据映射到 对象 @Entity(name = "t_comment") // 序列化,作用使数据不会出现乱码情况 public class Discuss implements Serializable { /** * @Id 表示 某属性 在数据表中是 主键 * @GeneratedValue : 与 @Id 标注在同一个位置用于表示属性对应主键生成策略 * 生成策略 : * TABLE (使用一个特定的数据库表来保存主键) * SEQUENCE (不支持主键自增的数据库主键生成策略) * INDETITY (主键自增) * AUTO (JPA 自动选择前面三个合适的策略,[默认选项]) * */ @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; private String content; private String author; /** * @Column : 对于属性和表字段不同时,使用 name 属性 将类属性 与 表字段属性对应 * */ @Column(name = "a_id") private Integer aId; // 省略 getter,setter 和 toString 方法 }创建 DiscussRepository 管理sql语句public interface DiscussRepository extends JpaRepository<Discuss, Integer> { // @Transactional 声明是一个事务,执行出错会回滚,控制事务 @Transactional @Modifying @Query(value = "update t_comment c set c.author=?1 where c.id=?2") public int updateDiscuss(String author,Integer id); }创建 DiscussService 缓存一些数据@Service public class DiscussService { // CommentRepository 继承自 JpaRepository 自带增删改查的方法 @Autowired private DiscussRepository discussRepository; // 通过id 查找 评论 // 缓存这个查询的结果,并以参数为缓存标识符(保证唯一) @Cacheable(cacheNames = "comment",unless = "#result==null") public Discuss findById(int id){ Optional<Discuss> discuss = discussRepository.findById(id); // 判断查询的类是否存在 当类存在时 则为 true if (discuss.isPresent()){ return discuss.get(); } return null; } // 更新评论 // 更新缓存,标识符为 评论id, result 表示评论 @CachePut(cacheNames = "comment",key = "#result.id") public Discuss updateDiscuss(Discuss discuss){ // 根据评论的 id 修改 author discussRepository.updateDiscuss(discuss.getAuthor(),discuss.getaId()); return discuss; } // 根据id 删除评论 // 清除缓存注解 @CacheEvict(cacheNames = "comment") public void deleteDiscuss(int discuss_id){ discussRepository.deleteById(discuss_id); } }创建 DiscussController 控制页面访问// 返回json格式字符串 @RestController public class DiscussController { // 注册组件 评论服务 @Autowired private DiscussService commentService; // 访问/get/id 可根据评论id 查找相对应的评论 // @PathVariable 自动映射 URL 绑定的占位符 {} @GetMapping("/get/{id}") public Discuss findById(@PathVariable("id") int comment_id){ Discuss discuss = commentService.findById(comment_id); return discuss; } @GetMapping("/update/{id}/{author}") public Discuss updateDiscuss(@PathVariable("id") int commet_id,@PathVariable("author") String author){ Discuss discuss = commentService.findById(commet_id); discuss.setAuthor(author); Discuss discuss1 = commentService.updateDiscuss(discuss); return discuss1; } @GetMapping("/delete/{id}") public void deleteDiscuss(@PathVariable("id") int comment_id){ commentService.deleteDiscuss(comment_id); } }运行结果{card-default label="提示" width="100%"}在浏览器中已经访问过http://127.0.0.1:8088/update/1/jerry,所以数据和刚插入的有所不同{/card-default}在浏览器中访问路径 http://127.0.0.1:8088/get/1控制台会输出redis 客户端也会进行缓存刷新浏览器,发现控制台不会再次输出sql语句更改访问路径信息http://127.0.0.1:8088/get/2redis 客户端会再次缓存数据
2022年04月24日
35 阅读
0 评论
0 点赞
2022-04-24
[Java] SpringBoot redis 缓存(初级)
下载 redis小皮面板(Windows系统)如果你是Linux系统 可以进入 官网下载 SpringBoot 项目添加依赖<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>添加配置信息application.propertiesspring.redis.host=127.0.0.1 spring.redis.port=6379 spring.redis.password=创建实体对象在model 包 或 domain 包下创建(规范)// Redis 缓存的键值名 @RedisHash("person") public class Person { // 实体对象的唯一表示 @Id private String id; // 标识对应属性在 Redis 中生成的二级索引 @Indexed private String name; public Person(String name) { this.name = name; } @Override public String toString() { return "Person{" + "id='" + id + '\'' + ", name='" + name + '\'' + '}'; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }创建 Repository方便管理对应的CRUD方法// Person 的 Repository public interface PersonRepository extends CrudRepository<Person, String> { // 查询所有的Person @Override List<Person> findAll(); // 通过id 查找 Person List<Person> findPeopleById(String id); // 通过 name 查找 Person List<Person> findPeopleByName(String name); }创建测试类 RedisTest@RunWith(SpringRunner.class) @SpringBootTest public class RedisTest { @Autowired private PersonRepository personRepository; @Test public void savePerson() { // 创建两个 Person 实体 Person person1 = new Person("张三"); Person person2 = new Person("李四"); // 保存两个实体 Person save1 = personRepository.save(person1); Person save2 = personRepository.save(person2); // 输出保存对象 System.out.println(save1); System.out.println(save2); } @Test public void selectPerson() { // 查询名叫张三的 Redis 缓存 System.out.println(personRepository.findPeopleByName("张三")); } @Test public void updatePerson() { // 查询名叫 张三 的Redis 缓存对象 Person person = personRepository.findPeopleByName("张三").get(0); // 修改对象的名字 person.setName("ZhangSan"); // 保存修改后的对象 Person save = personRepository.save(person); System.out.println(save); } @Test public void deletePerson() { // 查找名叫李四的Person 对象, 确保一定存在 Person person = personRepository.findPeopleByName("李四").get(0); // 删除对象 personRepository.delete(person); try { // 尝试再次获取 李四对象 Person del = personRepository.findPeopleByName("李四").get(0); System.out.println(del); } catch (Exception e) { // 没找到则会报错 System.out.println("删除成功"); } } }执行结果savePersonupdatePersondeletePerson
2022年04月24日
43 阅读
0 评论
0 点赞
1
2