├── .gitignore
├── README.md
├── pom.xml
├── spring-eureka-demo
├── eureka-consumer-service
│ ├── pom.xml
│ └── src
│ │ └── main
│ │ ├── java
│ │ └── com
│ │ │ └── example
│ │ │ └── eureka
│ │ │ ├── ConsumerApplication.java
│ │ │ ├── config
│ │ │ └── WebConfig.java
│ │ │ └── controller
│ │ │ └── RestTemplateController.java
│ │ └── resources
│ │ └── application.yml
├── eureka-producer-service
│ ├── pom.xml
│ └── src
│ │ └── main
│ │ ├── java
│ │ └── com
│ │ │ └── example
│ │ │ └── eureka
│ │ │ ├── ProducerApplication.java
│ │ │ └── controller
│ │ │ └── HelloController.java
│ │ └── resources
│ │ └── application.yml
├── eureka-server-duplicate
│ ├── pom.xml
│ └── src
│ │ └── main
│ │ ├── java
│ │ └── com
│ │ │ └── example
│ │ │ └── eureka
│ │ │ └── EurekaDuplicateServer.java
│ │ └── resources
│ │ └── application.yml
└── eureka-server
│ ├── pom.xml
│ └── src
│ └── main
│ ├── java
│ └── com
│ │ └── example
│ │ └── eureka
│ │ └── EurekaServer.java
│ └── resources
│ └── application.yml
├── spring-mongodb-demo
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── com
│ │ │ └── example
│ │ │ └── mongodb
│ │ │ ├── SpringMongodbApplication.java
│ │ │ ├── entity
│ │ │ ├── HistoryGoods.java
│ │ │ └── User.java
│ │ │ └── service
│ │ │ ├── UserService.java
│ │ │ └── impl
│ │ │ └── UserServiceImpl.java
│ └── resources
│ │ └── application.yml
│ └── test
│ └── java
│ └── com
│ └── example
│ └── mongodb
│ ├── MongoMergeTest.java
│ ├── MongoQueryTest.java
│ └── UserHistoryTest.java
├── spring-rabbitmq-demo
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── org
│ │ │ └── example
│ │ │ └── rabbitmq
│ │ │ ├── SpringRabbitmqApplication.java
│ │ │ ├── auto
│ │ │ ├── component
│ │ │ │ ├── RabbitConsumer.java
│ │ │ │ ├── RabbitDirectConsumer.java
│ │ │ │ ├── RabbitFanoutConsumer.java
│ │ │ │ ├── RabbitJsonConsumer.java
│ │ │ │ ├── RabbitProduce.java
│ │ │ │ └── RabbitTopicConsumer.java
│ │ │ ├── config
│ │ │ │ ├── JacksonConfig.java
│ │ │ │ └── RabbitmqConfig.java
│ │ │ └── entity
│ │ │ │ ├── Client.java
│ │ │ │ └── User.java
│ │ │ └── prototype
│ │ │ ├── Consumer.java
│ │ │ └── Producer.java
│ └── resources
│ │ └── application.yml
│ └── test
│ └── java
│ └── org
│ └── example
│ └── rabbitmq
│ └── auto
│ └── component
│ └── RabbitProduceTest.java
├── spring-security-demo
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── org
│ │ │ └── example
│ │ │ └── security
│ │ │ ├── SpringSecurityApplication.java
│ │ │ └── auth
│ │ │ ├── api
│ │ │ ├── AuthController.java
│ │ │ └── TestController.java
│ │ │ ├── bo
│ │ │ ├── AccessToken.java
│ │ │ ├── ApiPage.java
│ │ │ ├── ApiResult.java
│ │ │ ├── LoginInfo.java
│ │ │ └── PermissionInfoBO.java
│ │ │ ├── cache
│ │ │ ├── Cache.java
│ │ │ └── CaffeineCache.java
│ │ │ ├── component
│ │ │ ├── AccessDecisionProcessor.java
│ │ │ ├── InitProcessor.java
│ │ │ ├── JwtAuthenticationTokenFilter.java
│ │ │ ├── RestAuthenticationEntryPoint.java
│ │ │ └── RestfulAccessDeniedHandler.java
│ │ │ ├── config
│ │ │ ├── JacksonConfig.java
│ │ │ ├── MyConfig.java
│ │ │ └── SpringSecurityConfig.java
│ │ │ ├── constant
│ │ │ ├── ApiStatus.java
│ │ │ ├── CacheName.java
│ │ │ └── RoleEnum.java
│ │ │ ├── entity
│ │ │ ├── PermissionInfo.java
│ │ │ ├── RoleInfo.java
│ │ │ ├── UserDetail.java
│ │ │ └── UserInfo.java
│ │ │ ├── mapper
│ │ │ ├── PermissionMapper.java
│ │ │ ├── RoleInfoMapper.java
│ │ │ └── UserMapper.java
│ │ │ ├── properties
│ │ │ └── JwtProperties.java
│ │ │ ├── provider
│ │ │ ├── AuthProvider.java
│ │ │ └── JwtProvider.java
│ │ │ ├── service
│ │ │ ├── AuthService.java
│ │ │ ├── PermissionService.java
│ │ │ ├── RoleInfoService.java
│ │ │ ├── UserService.java
│ │ │ └── impl
│ │ │ │ ├── AuthServiceImpl.java
│ │ │ │ ├── CustomUserDetailsService.java
│ │ │ │ ├── PermissionServiceImpl.java
│ │ │ │ ├── RoleInfoServiceImpl.java
│ │ │ │ └── UserServiceImpl.java
│ │ │ └── util
│ │ │ └── JacksonUtil.java
│ └── resources
│ │ ├── application.yml
│ │ ├── doc
│ │ └── spring-boot-learning.sql
│ │ └── mapper
│ │ ├── PermissionMapper.xml
│ │ └── RoleInfoMapper.xml
│ └── test
│ └── java
│ └── org
│ └── example
│ └── security
│ └── UserServiceTest.java
├── spring-websocket
├── .gitignore
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── com
│ │ │ └── example
│ │ │ └── springwebsocket
│ │ │ ├── SpringWebsocketApplication.java
│ │ │ ├── TestController.java
│ │ │ ├── j2ee
│ │ │ ├── WebSocketConfig.java
│ │ │ └── WebSocketServer.java
│ │ │ ├── socketio
│ │ │ ├── SocketIoConfig.java
│ │ │ └── SocketIoHandle.java
│ │ │ └── spring
│ │ │ ├── SpringSocketConfig.java
│ │ │ └── SpringSocketHandle.java
│ └── resources
│ │ └── templates
│ │ ├── J2eeIndex.html
│ │ ├── SocketIoIndex.html
│ │ └── SpringIndex.html
│ └── test
│ └── java
│ └── com
│ └── example
│ └── springwebsocket
│ └── SpringWebsocketApplicationTests.java
└── spring-zookeeper-demo
├── zookeeper-consumer-service
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── com
│ │ └── example
│ │ └── zookeeper
│ │ ├── ZookeeperConsumerApplication.java
│ │ ├── config
│ │ └── WebConfig.java
│ │ └── controller
│ │ └── RestTemplateController.java
│ └── resources
│ └── application.yml
└── zookeeper-producer-service
├── pom.xml
└── src
└── main
├── java
└── com
│ └── example
│ └── zookeeper
│ ├── ZookeeperProducerApplication.java
│ └── controller
│ └── HelloController.java
└── resources
└── application.yml
/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 | .mvn/**
5 | !**/src/main/**
6 | !**/src/test/**
7 | log/
8 | logs/
9 | *.log
10 | mvnw
11 | mvnw.cmd
12 |
13 | ### STS ###
14 | .apt_generated
15 | .classpath
16 | .factorypath
17 | .project
18 | .settings
19 | .springBeans
20 | .sts4-cache
21 |
22 | ### IntelliJ IDEA ###
23 | .idea
24 | *.iws
25 | *.iml
26 | *.ipr
27 |
28 | ### NetBeans ###
29 | /nbproject/private/
30 | /nbbuild/
31 | /dist/
32 | /nbdist/
33 | /.nb-gradle/
34 | build/
35 |
36 | ### VS Code ###
37 | .vscode/
38 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Spring Boot Learning Demo
2 |
3 | [](https://spring.io/projects/spring-boot)
4 | [](https://www.oracle.com/java/technologies/javase/javase-jdk8-downloads.html)
5 | [](https://gitee.com/he-erduo/spring-boot-learning-demo)
6 | [](https://github.com/rookie-ricardo/spring-boot-learning-demo)
7 |
8 | 以 Spring Boot 为基础,构建多种Java项目实例,以实用为目的帮助大家快速上手 Spring Boot 开发,积累开发经验。
9 |
10 |
11 | ## Spring Boot Learning List
12 |
13 | * [spring-security-demo](/spring-security-demo):Spring Security + JWT 实现认证与动态鉴权。
14 |
15 | * **相关文章:**[SpringSecurity认证流程解析](https://juejin.im/post/5f01d648e51d45346a3ed1b7)
16 | * **相关文章:**[SpringSecurity动态鉴权解析](https://juejin.im/post/5f01dcb7f265da22a8514d0d)
17 | * **相关文章:**[SpringSecurity启动流程解析](https://juejin.im/post/5f0e75e36fb9a07e5a1c44aa)
18 | * **相关文章:**[SpringSecurity入口详解](https://juejin.cn/post/6960487717452906503)
19 |
20 | * [spring-rabbitmq-demo](/spring-rabbitmq-demo):Spring Boot + RabbitMQ 实现生产者消费者。
21 |
22 | * **相关文章:**[没用过消息队列?一文带你体验RabbitMQ收发消息](https://juejin.im/post/6856571028496351239)
23 | * **相关文章:**[刚体验完RabbitMQ?一文带你SpringBoot+RabbitMQ方式收发消息](https://juejin.im/post/6859152029823008781)
24 | * **相关文章:**[上手了RabbitMQ?再来看看它的交换机(Exchange)吧](https://juejin.im/post/6861959704705237000/)
25 | * **相关文章:**[RabbitMQ高级之如何保证消息可靠性?](https://juejin.im/post/6862875289786662926)
26 | * **相关文章:**[RabbitMQ高级之消息限流与延时队列](https://juejin.im/post/6864360098077081613)
27 |
28 | * [spring-websocket](/spring-websocket):Spring Boot / J2EE + WebSocket 实现常用功能。
29 |
30 | * **相关文章:**[一文搞懂四种 WebSocket 使用方式](https://juejin.cn/post/7095940082187632677)
31 | ---
32 |
33 | 注:项目相关数据库文件都放在demo下的resource下的doc文件下。
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 | * 用户对象 14 | *
15 | * 16 | * @author 和耳朵 17 | * @since 2020-09-01 18 | */ 19 | @Data 20 | @Document(collection = "user") 21 | public class User { 22 | 23 | @Id 24 | private String id = UUID.randomUUID().toString(); 25 | 26 | private String username = "和耳朵"; 27 | 28 | private String password = "123456"; 29 | 30 | private Integer activeStatus = 1; 31 | 32 | private LocalDateTime createTime = LocalDateTime.now(); 33 | 34 | private List19 | * MongoTemplateTest 20 | *
21 | * 22 | * @author 和耳朵 23 | * @since 2020-10-14 24 | */ 25 | @SpringBootTest 26 | public class MongoMergeTest { 27 | @Autowired 28 | private MongoTemplate mongoTemplate; 29 | 30 | /** 31 | * 保存数据 32 | */ 33 | @Test 34 | public void save() { 35 | User user = new User(); 36 | User save = mongoTemplate.insert(user); 37 | System.out.println(save); 38 | } 39 | 40 | /** 41 | * 批量保存数据 42 | */ 43 | @Test 44 | public void saveBatch() { 45 | User user1 = new User(); 46 | User user2 = new User(); 47 | User user3 = new User(); 48 | Collection16 | * MongoTemplateTest 17 | *
18 | * 19 | * @author 和耳朵 20 | * @since 2020-10-14 21 | */ 22 | @SpringBootTest 23 | public class MongoQueryTest { 24 | @Autowired 25 | private MongoTemplate mongoTemplate; 26 | 27 | /** 28 | * 单查 29 | */ 30 | @Test 31 | public void find() { 32 | User user = mongoTemplate.findById("d3d24091-30fe-4272-ab70-88fa475a62dd", User.class); 33 | System.out.println(user); 34 | } 35 | 36 | /** 37 | * 按条件查询数据 38 | */ 39 | @Test 40 | public void findBy1() { 41 | // 查询的范围 42 | Query query = Query.query(Criteria.where("activeStatus").is(1)); 43 | 44 | List16 | * MongoTemplateTest 17 | *
18 | * 19 | * @author 和耳朵 20 | * @since 2020-10-14 21 | */ 22 | @SpringBootTest 23 | public class UserHistoryTest { 24 | @Autowired 25 | private MongoTemplate mongoTemplate; 26 | @Autowired 27 | private UserService userService; 28 | 29 | /** 30 | * 批量保存数据 6d053675-5fba-4338-9577-02810c3413d1 31 | */ 32 | @Test 33 | public void saveBatch() { 34 | for (int i = 0; i < 2000; i++) { 35 | User user = new User(); 36 | System.out.println(user.getId()); 37 | List12 | * 13 | *
14 | * 15 | * @author 和耳朵 16 | * @since 2020-07-29 21:01 17 | */ 18 | @Slf4j 19 | @Component("rabbitConsumer") 20 | public class RabbitConsumer { 21 | 22 | @RabbitListener(queues = Producer.QUEUE_NAME) 23 | public void onMessage(Message message, Channel channel) throws Exception { 24 | System.out.println("Message content : " + message); 25 | channel.basicAck(message.getMessageProperties().getDeliveryTag(),false); 26 | System.out.println("消息已确认"); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /spring-rabbitmq-demo/src/main/java/org/example/rabbitmq/auto/component/RabbitDirectConsumer.java: -------------------------------------------------------------------------------- 1 | package org.example.rabbitmq.auto.component; 2 | 3 | import com.rabbitmq.client.Channel; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.amqp.core.Message; 6 | import org.springframework.amqp.rabbit.annotation.RabbitListener; 7 | import org.springframework.stereotype.Component; 8 | 9 | /** 10 | *11 | * 12 | *
13 | * 14 | * @author 和耳朵 15 | * @since 2020-08-17 21:01 16 | */ 17 | @Slf4j 18 | @Component("rabbitDirectConsumer") 19 | public class RabbitDirectConsumer { 20 | @RabbitListener(queues = "directQueue1") 21 | public void onMessage1(Message message, Channel channel) throws Exception { 22 | log.info("Message content : " + message); 23 | channel.basicAck(message.getMessageProperties().getDeliveryTag(),false); 24 | log.info("消息已确认"); 25 | } 26 | 27 | @RabbitListener(queues = "directQueue2") 28 | public void onMessage2(Message message, Channel channel) throws Exception { 29 | log.info("Message content : " + message); 30 | channel.basicAck(message.getMessageProperties().getDeliveryTag(),false); 31 | log.info("消息已确认"); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /spring-rabbitmq-demo/src/main/java/org/example/rabbitmq/auto/component/RabbitFanoutConsumer.java: -------------------------------------------------------------------------------- 1 | package org.example.rabbitmq.auto.component; 2 | 3 | import com.rabbitmq.client.Channel; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.example.rabbitmq.auto.entity.Client; 6 | import org.example.rabbitmq.prototype.Producer; 7 | import org.springframework.amqp.core.Message; 8 | import org.springframework.amqp.rabbit.annotation.RabbitHandler; 9 | import org.springframework.amqp.rabbit.annotation.RabbitListener; 10 | import org.springframework.amqp.support.AmqpHeaders; 11 | import org.springframework.messaging.handler.annotation.Headers; 12 | import org.springframework.stereotype.Component; 13 | 14 | import java.util.Map; 15 | 16 | /** 17 | *18 | * 19 | *
20 | * 21 | * @author 和耳朵 22 | * @since 2020-08-13 21:01 23 | */ 24 | @Slf4j 25 | @Component("rabbitFanoutConsumer") 26 | public class RabbitFanoutConsumer { 27 | @RabbitListener(queues = "fanout1") 28 | public void onMessage1(Message message, Channel channel) throws Exception { 29 | log.info("Message content : " + message); 30 | channel.basicAck(message.getMessageProperties().getDeliveryTag(),false); 31 | log.info("消息已确认"); 32 | } 33 | 34 | @RabbitListener(queues = "fanout2") 35 | public void onMessage2(Message message, Channel channel) throws Exception { 36 | log.info("Message content : " + message); 37 | channel.basicAck(message.getMessageProperties().getDeliveryTag(),false); 38 | log.info("消息已确认"); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /spring-rabbitmq-demo/src/main/java/org/example/rabbitmq/auto/component/RabbitJsonConsumer.java: -------------------------------------------------------------------------------- 1 | package org.example.rabbitmq.auto.component; 2 | 3 | import com.rabbitmq.client.Channel; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.example.rabbitmq.auto.entity.Client; 6 | import org.springframework.amqp.rabbit.annotation.RabbitHandler; 7 | import org.springframework.amqp.rabbit.annotation.RabbitListener; 8 | import org.springframework.amqp.support.AmqpHeaders; 9 | import org.springframework.messaging.handler.annotation.Headers; 10 | import org.springframework.stereotype.Component; 11 | 12 | import java.util.Map; 13 | 14 | /** 15 | *16 | * 17 | *
18 | * 19 | * @author 和耳朵 20 | * @since 2020-07-29 21:01 21 | */ 22 | @Slf4j 23 | @Component("rabbitJsonConsumer") 24 | @RabbitListener(queues = RabbitJsonConsumer.JSON_QUEUE) 25 | public class RabbitJsonConsumer { 26 | public static final String JSON_QUEUE = "erduo_json"; 27 | 28 | @RabbitHandler 29 | public void onMessage(Client client, @Headers Map21 | * 22 | *
23 | * 24 | * @author 和耳朵 25 | * @since 2020-07-29 21:01 26 | */ 27 | @Slf4j 28 | @Component("rabbitProduce") 29 | public class RabbitProduce { 30 | @Autowired 31 | private RabbitTemplate rabbitTemplate; 32 | 33 | public void send() { 34 | String message = "Hello 我是作者和耳朵,欢迎关注我。" + LocalDateTime.now().toString(); 35 | 36 | System.out.println("Message content : " + message); 37 | 38 | // 指定消息类型 39 | MessageProperties props = MessagePropertiesBuilder.newInstance() 40 | .setContentType(MessageProperties.CONTENT_TYPE_TEXT_PLAIN).build(); 41 | 42 | rabbitTemplate.send(Producer.QUEUE_NAME,new Message(message.getBytes(StandardCharsets.UTF_8),props)); 43 | System.out.println("消息发送完毕。"); 44 | } 45 | 46 | public void convertAndSend() { 47 | User user = new User(); 48 | 49 | System.out.println("Message content : " + user); 50 | 51 | rabbitTemplate.convertAndSend(Producer.QUEUE_NAME,user); 52 | System.out.println("消息发送完毕。"); 53 | } 54 | 55 | public void sendObject() { 56 | Client client = new Client(); 57 | 58 | System.out.println("Message content : " + client); 59 | 60 | rabbitTemplate.convertAndSend(RabbitJsonConsumer.JSON_QUEUE,client); 61 | System.out.println("消息发送完毕。"); 62 | } 63 | 64 | public void sendFanout() { 65 | Client client = new Client(); 66 | 67 | // 应读者要求,以后代码打印的地方都会改成log方式,这是一种良好的编程习惯,用System.out.println一般是不推荐的。 68 | log.info("Message content : " + client); 69 | 70 | rabbitTemplate.convertAndSend("fanoutExchange",null,client); 71 | System.out.println("消息发送完毕。"); 72 | } 73 | 74 | public void sendDirect() { 75 | Client client = new Client(); 76 | 77 | log.info("Message content : " + client); 78 | 79 | rabbitTemplate.convertAndSend("directExchange","sms",client); 80 | System.out.println("消息发送完毕。"); 81 | } 82 | 83 | public void sendTopic() { 84 | Client client = new Client(); 85 | 86 | log.info("Message content : " + client); 87 | 88 | rabbitTemplate.convertAndSend("topicExchange","sms.liantong",client); 89 | System.out.println("消息发送完毕。"); 90 | } 91 | 92 | public void sendAndConfirm() { 93 | User user = new User(); 94 | 95 | log.info("Message content : " + user); 96 | 97 | CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString()); 98 | rabbitTemplate.convertAndSend(Producer.QUEUE_NAME,user,correlationData); 99 | log.info("消息发送完毕。"); 100 | 101 | rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback(){ 102 | @Override 103 | public void confirm(CorrelationData correlationData, boolean ack, String cause) { 104 | log.info("CorrelationData content : " + correlationData); 105 | log.info("Ack status : " + ack); 106 | log.info("Cause content : " + cause); 107 | if(ack){ 108 | log.info("消息成功发送,订单入库,更改订单状态"); 109 | }else{ 110 | log.info("消息发送失败:"+correlationData+", 出现异常:"+cause); 111 | } 112 | } 113 | }); 114 | } 115 | 116 | public void sendAndReturn() { 117 | User user = new User(); 118 | 119 | log.info("Message content : " + user); 120 | 121 | rabbitTemplate.setReturnCallback((message, replyCode, replyText, exchange, routingKey) -> { 122 | log.info("被退回的消息为:{}", message); 123 | log.info("replyCode:{}", replyCode); 124 | log.info("replyText:{}", replyText); 125 | log.info("exchange:{}", exchange); 126 | log.info("routingKey:{}", routingKey); 127 | }); 128 | 129 | rabbitTemplate.convertAndSend("fail", user); 130 | log.info("消息发送完毕。"); 131 | } 132 | 133 | public void sendTtl() { 134 | String message = "Hello 我是作者和耳朵,欢迎关注我。" + LocalDateTime.now().toString(); 135 | 136 | System.out.println("Message content : " + message); 137 | 138 | // 设置过期3s 139 | MessageProperties props = MessagePropertiesBuilder.newInstance() 140 | .setExpiration("3000").build(); 141 | 142 | rabbitTemplate.send(Producer.QUEUE_NAME, new Message(message.getBytes(StandardCharsets.UTF_8), props)); 143 | System.out.println("消息发送完毕。"); 144 | } 145 | 146 | } 147 | -------------------------------------------------------------------------------- /spring-rabbitmq-demo/src/main/java/org/example/rabbitmq/auto/component/RabbitTopicConsumer.java: -------------------------------------------------------------------------------- 1 | package org.example.rabbitmq.auto.component; 2 | 3 | import com.rabbitmq.client.Channel; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.amqp.core.Message; 6 | import org.springframework.amqp.rabbit.annotation.RabbitListener; 7 | import org.springframework.stereotype.Component; 8 | 9 | /** 10 | *11 | * 12 | *
13 | * 14 | * @author 和耳朵 15 | * @since 2020-08-17 22:01 16 | */ 17 | @Slf4j 18 | @Component("rabbitTopicConsumer") 19 | public class RabbitTopicConsumer { 20 | @RabbitListener(queues = "topicQueue1") 21 | public void onMessage1(Message message, Channel channel) throws Exception { 22 | log.info("Message content : " + message); 23 | channel.basicAck(message.getMessageProperties().getDeliveryTag(),false); 24 | log.info("消息已确认"); 25 | } 26 | 27 | @RabbitListener(queues = "topicQueue2") 28 | public void onMessage2(Message message, Channel channel) throws Exception { 29 | log.info("Message content : " + message); 30 | channel.basicAck(message.getMessageProperties().getDeliveryTag(),false); 31 | log.info("消息已确认"); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /spring-rabbitmq-demo/src/main/java/org/example/rabbitmq/auto/config/JacksonConfig.java: -------------------------------------------------------------------------------- 1 | package org.example.rabbitmq.auto.config; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | import com.fasterxml.jackson.core.JsonParser; 5 | import com.fasterxml.jackson.databind.DeserializationFeature; 6 | import com.fasterxml.jackson.databind.ObjectMapper; 7 | import com.fasterxml.jackson.databind.SerializationFeature; 8 | import com.fasterxml.jackson.databind.module.SimpleModule; 9 | import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; 10 | import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; 11 | import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer; 12 | import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; 13 | import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer; 14 | import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer; 15 | import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; 16 | import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer; 17 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 18 | import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer; 19 | import org.springframework.context.annotation.Bean; 20 | import org.springframework.context.annotation.Configuration; 21 | import org.springframework.context.annotation.Primary; 22 | import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; 23 | 24 | import java.math.BigInteger; 25 | import java.time.LocalDate; 26 | import java.time.LocalDateTime; 27 | import java.time.LocalTime; 28 | import java.time.ZoneId; 29 | import java.time.format.DateTimeFormatter; 30 | import java.util.Locale; 31 | import java.util.TimeZone; 32 | 33 | /** 34 | *35 | * 针对Jackson做的个性化配置 36 | *
37 | * 38 | * @author rookie.zhang 39 | * @since 2020-03-13 40 | */ 41 | @Configuration 42 | public class JacksonConfig { 43 | 44 | @Bean 45 | public Jackson2ObjectMapperBuilderCustomizer customizer() { 46 | return builder -> { 47 | builder.locale(Locale.CHINA); 48 | builder.timeZone(TimeZone.getTimeZone(ZoneId.systemDefault())); 49 | builder.simpleDateFormat("yyyy-MM-dd HH:mm:ss"); 50 | 51 | JavaTimeModule javaTimeModule = new JavaTimeModule(); 52 | javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); 53 | javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd"))); 54 | javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern("HH:mm:ss"))); 55 | javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); 56 | javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd"))); 57 | javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern("HH:mm:ss"))); 58 | 59 | builder.modules(javaTimeModule); 60 | }; 61 | } 62 | 63 | 64 | @Bean 65 | @Primary 66 | @ConditionalOnMissingBean(ObjectMapper.class) 67 | public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) 68 | { 69 | ObjectMapper objectMapper = builder.createXmlMapper(false).build(); 70 | 71 | // 通过该方法对mapper对象进行设置,所有序列化的对象都将按改规则进行系列化 72 | // Include.Include.ALWAYS 默认 73 | // Include.NON_DEFAULT 属性为默认值不序列化 74 | // Include.NON_EMPTY 属性为 空("") 或者为 NULL 都不序列化,则返回的json是没有这个字段的 75 | // Include.NON_NULL 属性为NULL 不序列化 76 | objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); 77 | // 允许出现特殊字符和转义符 78 | objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true); 79 | // 允许出现单引号 80 | objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true); 81 | objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); 82 | objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); 83 | 84 | SimpleModule simpleModule = new SimpleModule(); 85 | /** 86 | * 将Long,BigInteger序列化的时候,转化为String 87 | */ 88 | simpleModule.addSerializer(Long.class, ToStringSerializer.instance); 89 | simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance); 90 | simpleModule.addSerializer(BigInteger.class, ToStringSerializer.instance); 91 | 92 | objectMapper.registerModule(simpleModule); 93 | 94 | return objectMapper; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /spring-rabbitmq-demo/src/main/java/org/example/rabbitmq/auto/config/RabbitmqConfig.java: -------------------------------------------------------------------------------- 1 | package org.example.rabbitmq.auto.config; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | import org.springframework.amqp.core.*; 5 | import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter; 6 | import org.springframework.amqp.support.converter.MessageConverter; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.context.annotation.Configuration; 10 | 11 | import java.util.HashMap; 12 | import java.util.Map; 13 | 14 | /** 15 | *16 | * 17 | *
18 | * 19 | * @author 和耳朵 20 | * @since 2020-07-29 21:01 21 | */ 22 | @Configuration 23 | public class RabbitmqConfig { 24 | @Autowired 25 | private ObjectMapper jacksonObjectMapper; 26 | 27 | @Bean 28 | public Queue erduo() { 29 | // 其三个参数:durable exclusive autoDelete 30 | // 一般只设置一下持久化即可 31 | return new Queue("erduo",true); 32 | } 33 | 34 | @Bean 35 | public Queue erduoJson() { 36 | // 其三个参数:durable exclusive autoDelete 37 | // 一般只设置一下持久化即可 38 | return new Queue("erduo_json",true); 39 | } 40 | 41 | // 扇形交换机示例 42 | @Bean 43 | public Queue fanout1() { 44 | return new Queue("fanout1"); 45 | } 46 | 47 | @Bean 48 | public Queue fanout2() { 49 | return new Queue("fanout2"); 50 | } 51 | 52 | @Bean 53 | public FanoutExchange fanoutExchange() { 54 | // 三个构造参数:name durable autoDelete 55 | return new FanoutExchange("fanoutExchange", false, false); 56 | } 57 | 58 | @Bean 59 | public Binding binding1() { 60 | return BindingBuilder.bind(fanout1()).to(fanoutExchange()); 61 | } 62 | 63 | @Bean 64 | public Binding binding2() { 65 | return BindingBuilder.bind(fanout2()).to(fanoutExchange()); 66 | } 67 | 68 | // 直接交换机示例 69 | @Bean 70 | public Queue directQueue1() { 71 | return new Queue("directQueue1"); 72 | } 73 | 74 | @Bean 75 | public Queue directQueue2() { 76 | return new Queue("directQueue2"); 77 | } 78 | 79 | @Bean 80 | public DirectExchange directExchange() { 81 | // 三个构造参数:name durable autoDelete 82 | return new DirectExchange("directExchange", false, false); 83 | } 84 | 85 | @Bean 86 | public Binding directBinding1() { 87 | return BindingBuilder.bind(directQueue1()).to(directExchange()).with("sms"); 88 | } 89 | 90 | @Bean 91 | public Binding directBinding2() { 92 | return BindingBuilder.bind(directQueue2()).to(directExchange()).with("mail"); 93 | } 94 | 95 | // 主题交换机示例 96 | @Bean 97 | public Queue topicQueue1() { 98 | return new Queue("topicQueue1"); 99 | } 100 | 101 | @Bean 102 | public Queue topicQueue2() { 103 | return new Queue("topicQueue2"); 104 | } 105 | 106 | @Bean 107 | public TopicExchange topicExchange() { 108 | // 三个构造参数:name durable autoDelete 109 | return new TopicExchange("topicExchange", false, false); 110 | } 111 | 112 | @Bean 113 | public Binding topicBinding1() { 114 | return BindingBuilder.bind(topicQueue1()).to(topicExchange()).with("sms.*"); 115 | } 116 | 117 | @Bean 118 | public Binding topicBinding2() { 119 | return BindingBuilder.bind(topicQueue2()).to(topicExchange()).with("mail.#"); 120 | } 121 | 122 | // TTL队列示例 123 | @Bean 124 | public Queue ttlQueue() { 125 | Map18 | * 认证 19 | *
20 | * 21 | * @author 和耳朵 22 | * @since 2020-06-30 23 | */ 24 | @RestController 25 | @RequestMapping("/api/auth") 26 | public class AuthController { 27 | 28 | @Autowired 29 | private AuthService authService; 30 | @Autowired 31 | private JwtProvider jwtProvider; 32 | 33 | /** 34 | * 登录方法 35 | *36 | * loginAccount:user 37 | * password:123456 38 | * 39 | * @param loginInfo 40 | * @return ApiResult 41 | */ 42 | @PostMapping("/login") 43 | public ApiResult login(@Valid @RequestBody LoginInfo loginInfo) { 44 | return authService.login(loginInfo.getLoginAccount(), loginInfo.getPassword()); 45 | } 46 | 47 | @PostMapping("/logout") 48 | public ApiResult logout() { 49 | return authService.logout(); 50 | } 51 | 52 | @PostMapping("/refresh") 53 | public ApiResult refreshToken(HttpServletRequest request) { 54 | return authService.refreshToken(jwtProvider.getToken(request)); 55 | } 56 | 57 | 58 | } 59 | -------------------------------------------------------------------------------- /spring-security-demo/src/main/java/org/example/security/auth/api/TestController.java: -------------------------------------------------------------------------------- 1 | package org.example.security.auth.api; 2 | 3 | import org.example.security.auth.bo.ApiResult; 4 | import org.springframework.web.bind.annotation.GetMapping; 5 | import org.springframework.web.bind.annotation.RestController; 6 | 7 | @RestController 8 | public class TestController { 9 | 10 | @GetMapping("/api/anon") 11 | public ApiResult test01() { 12 | return ApiResult.ok("匿名访问成功"); 13 | } 14 | 15 | @GetMapping("/api/user") 16 | public ApiResult test02() { 17 | return ApiResult.ok("USER用户访问成功"); 18 | } 19 | 20 | @GetMapping("/api/admin") 21 | public ApiResult test03() { 22 | return ApiResult.ok("管理员用户访问成功"); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /spring-security-demo/src/main/java/org/example/security/auth/bo/AccessToken.java: -------------------------------------------------------------------------------- 1 | package org.example.security.auth.bo; 2 | 3 | import lombok.Builder; 4 | import lombok.Data; 5 | 6 | import java.util.Date; 7 | 8 | @Data 9 | @Builder 10 | public class AccessToken { 11 | private String loginAccount; 12 | private String token; 13 | private Date expirationTime; 14 | } 15 | -------------------------------------------------------------------------------- /spring-security-demo/src/main/java/org/example/security/auth/bo/ApiPage.java: -------------------------------------------------------------------------------- 1 | package org.example.security.auth.bo; 2 | 3 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 4 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | *
10 | * Api分页工具类 11 | *
12 | * 13 | * @author 和耳朵 14 | * @since 2020-06-05 15 | */ 16 | @JsonIgnoreProperties(value = {"records", "total", "size", "current", "records", "searchCount", "orders"}) 17 | public class ApiPage7 | * 8 | *
9 | * 10 | * @author 和耳朵 11 | * @since 2020-07-05 19:05 12 | */ 13 | @Data 14 | public class PermissionInfoBO { 15 | 16 | private String id; 17 | 18 | private String permissionName; 19 | 20 | private String permissionUri; 21 | 22 | private String permissionMethod; 23 | 24 | private String roleName; 25 | 26 | private String roleCode; 27 | } 28 | -------------------------------------------------------------------------------- /spring-security-demo/src/main/java/org/example/security/auth/cache/Cache.java: -------------------------------------------------------------------------------- 1 | package org.example.security.auth.cache; 2 | 3 | import org.example.security.auth.constant.CacheName; 4 | 5 | /** 6 | *7 | * Cache接口 8 | *
9 | * 10 | * @author 和耳朵 11 | * @since 2020-06-30 12 | */ 13 | public interface Cache { 14 | 15 |13 | * CaffeineCache实现类 14 | *
15 | * 16 | * @author 和耳朵 17 | * @since 2020-06-30 18 | */ 19 | @Slf4j 20 | @Service("caffeineCache") 21 | public class CaffeineCache implements Cache { 22 | @Autowired 23 | private CacheManager caffeineCacheManager; 24 | 25 | 26 | @Override 27 | public23 | * JWT登录过滤器 24 | *
25 | *26 | * 拿到请求头中的token解析出其中的用户信息, 27 | * 将用户信息传给下一条过滤器, 28 | * 拿到上下文对象赋值到上下文。 29 | *
30 | * 31 | * @author 和耳朵 32 | * @since 2020-06-30 33 | */ 34 | @Slf4j 35 | public class JwtAuthenticationTokenFilter extends OncePerRequestFilter { 36 | 37 | @Autowired 38 | private JwtProvider jwtProvider; 39 | @Autowired 40 | private JwtProperties jwtProperties; 41 | @Autowired 42 | private Cache caffeineCache; 43 | 44 | @Override 45 | protected void doFilterInternal(HttpServletRequest request, 46 | HttpServletResponse response, 47 | FilterChain chain) throws ServletException, IOException { 48 | log.info("JWT过滤器通过校验请求头token进行自动登录..."); 49 | 50 | // 拿到Authorization请求头内的信息 51 | String authToken = jwtProvider.getToken(request); 52 | 53 | // 判断一下内容是否为空 54 | if (StrUtil.isNotEmpty(authToken) && authToken.startsWith(jwtProperties.getTokenPrefix())) { 55 | // 去掉token前缀(Bearer ),拿到真实token 56 | authToken = authToken.substring(jwtProperties.getTokenPrefix().length()); 57 | 58 | // 拿到token里面的登录账号 59 | String loginAccount = jwtProvider.getSubjectFromToken(authToken); 60 | 61 | if (StrUtil.isNotEmpty(loginAccount) && SecurityContextHolder.getContext().getAuthentication() == null) { 62 | // 查询用户 63 | UserDetail userDetails = caffeineCache.get(CacheName.USER, loginAccount, UserDetail.class); 64 | 65 | // 拿到用户信息后验证用户信息与token 66 | if (userDetails != null && jwtProvider.validateToken(authToken, userDetails)) { 67 | 68 | // 组装authentication对象,构造参数是Principal Credentials 与 Authorities 69 | // 后面的拦截器里面会用到 grantedAuthorities 方法 70 | UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, userDetails.getPassword(), userDetails.getAuthorities()); 71 | 72 | // 将authentication信息放入到上下文对象中 73 | SecurityContextHolder.getContext().setAuthentication(authentication); 74 | 75 | log.info("JWT过滤器通过校验请求头token自动登录成功, user : {}", userDetails.getUsername()); 76 | } 77 | } 78 | } 79 | 80 | chain.doFilter(request, response); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /spring-security-demo/src/main/java/org/example/security/auth/component/RestAuthenticationEntryPoint.java: -------------------------------------------------------------------------------- 1 | package org.example.security.auth.component; 2 | 3 | import org.example.security.auth.bo.ApiResult; 4 | import org.example.security.auth.util.JacksonUtil; 5 | import org.springframework.security.core.AuthenticationException; 6 | import org.springframework.security.web.AuthenticationEntryPoint; 7 | 8 | import javax.servlet.ServletException; 9 | import javax.servlet.http.HttpServletRequest; 10 | import javax.servlet.http.HttpServletResponse; 11 | import java.io.IOException; 12 | 13 | /** 14 | *
15 | * 用户未登录异常处理类 16 | *
17 | * 当用户尝试访问需要权限才能的REST资源而不提供Token或者Token错误或者过期时, 18 | * 将调用此方法发送401响应以及错误信息 19 | * 20 | * @author 和耳朵 21 | * @since 2020-06-30 22 | */ 23 | public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint { 24 | 25 | @Override 26 | public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { 27 | response.setHeader("Cache-Control", "no-cache"); 28 | response.setCharacterEncoding("UTF-8"); 29 | response.setContentType("application/json"); 30 | response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); 31 | response.getWriter().println(JacksonUtil.toJsonString(ApiResult.fail(authException.getMessage()))); 32 | response.getWriter().flush(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /spring-security-demo/src/main/java/org/example/security/auth/component/RestfulAccessDeniedHandler.java: -------------------------------------------------------------------------------- 1 | package org.example.security.auth.component; 2 | 3 | import org.example.security.auth.bo.ApiResult; 4 | import org.example.security.auth.constant.ApiStatus; 5 | import org.example.security.auth.util.JacksonUtil; 6 | import org.springframework.security.access.AccessDeniedException; 7 | import org.springframework.security.web.access.AccessDeniedHandler; 8 | 9 | import javax.servlet.ServletException; 10 | import javax.servlet.http.HttpServletRequest; 11 | import javax.servlet.http.HttpServletResponse; 12 | import java.io.IOException; 13 | 14 | /** 15 | *16 | * 权限不足异常处理类 17 | *
18 | * 当用户尝试访问需要权限才能的REST资源而权限不足的时候, 19 | * 将调用此方法发送403响应以及错误信息 20 | * 21 | * @author 和耳朵 22 | * @since 2020-06-30 23 | */ 24 | public class RestfulAccessDeniedHandler implements AccessDeniedHandler { 25 | 26 | @Override 27 | public void handle(HttpServletRequest request, 28 | HttpServletResponse response, 29 | AccessDeniedException e) throws IOException, ServletException { 30 | 31 | response.setHeader("Cache-Control", "no-cache"); 32 | response.setCharacterEncoding("UTF-8"); 33 | response.setContentType("application/json"); 34 | response.setStatus(HttpServletResponse.SC_FORBIDDEN); 35 | response.getWriter().println(JacksonUtil.toJsonString(ApiResult.instance(ApiStatus.NOT_PERMISSION))); 36 | response.getWriter().flush(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /spring-security-demo/src/main/java/org/example/security/auth/config/JacksonConfig.java: -------------------------------------------------------------------------------- 1 | package org.example.security.auth.config; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | import com.fasterxml.jackson.core.JsonParser; 5 | import com.fasterxml.jackson.databind.DeserializationFeature; 6 | import com.fasterxml.jackson.databind.ObjectMapper; 7 | import com.fasterxml.jackson.databind.SerializationFeature; 8 | import com.fasterxml.jackson.databind.module.SimpleModule; 9 | import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; 10 | import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; 11 | import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer; 12 | import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; 13 | import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer; 14 | import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer; 15 | import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; 16 | import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer; 17 | import org.example.security.auth.util.JacksonUtil; 18 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 19 | import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer; 20 | import org.springframework.context.annotation.Bean; 21 | import org.springframework.context.annotation.Configuration; 22 | import org.springframework.context.annotation.Primary; 23 | import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; 24 | 25 | import java.math.BigInteger; 26 | import java.time.LocalDate; 27 | import java.time.LocalDateTime; 28 | import java.time.LocalTime; 29 | import java.time.ZoneId; 30 | import java.time.format.DateTimeFormatter; 31 | import java.util.Locale; 32 | import java.util.TimeZone; 33 | 34 | /** 35 | *36 | * 针对Jackson做的个性化配置 37 | *
38 | * 39 | * @author rookie.zhang 40 | * @since 2020-03-13 41 | */ 42 | @Configuration 43 | public class JacksonConfig { 44 | 45 | @Bean 46 | public Jackson2ObjectMapperBuilderCustomizer customizer() { 47 | return builder -> { 48 | builder.locale(Locale.CHINA); 49 | builder.timeZone(TimeZone.getTimeZone(ZoneId.systemDefault())); 50 | builder.simpleDateFormat("yyyy-MM-dd HH:mm:ss"); 51 | 52 | JavaTimeModule javaTimeModule = new JavaTimeModule(); 53 | javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); 54 | javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd"))); 55 | javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern("HH:mm:ss"))); 56 | javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); 57 | javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd"))); 58 | javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern("HH:mm:ss"))); 59 | 60 | builder.modules(javaTimeModule); 61 | }; 62 | } 63 | 64 | 65 | @Bean 66 | @Primary 67 | @ConditionalOnMissingBean(ObjectMapper.class) 68 | public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) 69 | { 70 | ObjectMapper objectMapper = builder.createXmlMapper(false).build(); 71 | 72 | // 通过该方法对mapper对象进行设置,所有序列化的对象都将按改规则进行系列化 73 | // Include.Include.ALWAYS 默认 74 | // Include.NON_DEFAULT 属性为默认值不序列化 75 | // Include.NON_EMPTY 属性为 空("") 或者为 NULL 都不序列化,则返回的json是没有这个字段的 76 | // Include.NON_NULL 属性为NULL 不序列化 77 | objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); 78 | // 允许出现特殊字符和转义符 79 | objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true); 80 | // 允许出现单引号 81 | objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true); 82 | objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); 83 | objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); 84 | 85 | SimpleModule simpleModule = new SimpleModule(); 86 | /** 87 | * 将Long,BigInteger序列化的时候,转化为String 88 | */ 89 | simpleModule.addSerializer(Long.class, ToStringSerializer.instance); 90 | simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance); 91 | simpleModule.addSerializer(BigInteger.class, ToStringSerializer.instance); 92 | 93 | objectMapper.registerModule(simpleModule); 94 | 95 | // 将工具类中的 objectMapper 换为 Spring 中的 objectMapper 96 | JacksonUtil.objectMapper = objectMapper; 97 | return objectMapper; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /spring-security-demo/src/main/java/org/example/security/auth/config/MyConfig.java: -------------------------------------------------------------------------------- 1 | package org.example.security.auth.config; 2 | 3 | import com.github.benmanes.caffeine.cache.CacheLoader; 4 | import com.github.benmanes.caffeine.cache.Caffeine; 5 | import org.example.security.auth.constant.CacheName; 6 | import org.example.security.auth.properties.JwtProperties; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.cache.CacheManager; 9 | import org.springframework.cache.caffeine.CaffeineCacheManager; 10 | import org.springframework.context.annotation.Bean; 11 | import org.springframework.context.annotation.Configuration; 12 | import org.springframework.web.cors.CorsConfiguration; 13 | import org.springframework.web.cors.UrlBasedCorsConfigurationSource; 14 | import org.springframework.web.filter.CorsFilter; 15 | 16 | import java.util.concurrent.TimeUnit; 17 | 18 | /** 19 | *20 | * 配置文件 21 | *
22 | * 23 | * @author 和耳朵 24 | * @since 2020-06-30 25 | */ 26 | @Configuration 27 | public class MyConfig { 28 | @Autowired 29 | private JwtProperties jwtProperties; 30 | 31 | @Bean 32 | public CorsFilter corsFilter() { 33 | final UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource(); 34 | final CorsConfiguration corsConfiguration = new CorsConfiguration(); 35 | /*是否允许请求带有验证信息*/ 36 | corsConfiguration.setAllowCredentials(true); 37 | /*允许访问的客户端域名*/ 38 | corsConfiguration.addAllowedOrigin("*"); 39 | /*允许服务端访问的客户端请求头*/ 40 | corsConfiguration.addAllowedHeader("*"); 41 | /*允许访问的方法名,GET POST等*/ 42 | corsConfiguration.addAllowedMethod("*"); 43 | urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration); 44 | return new CorsFilter(urlBasedCorsConfigurationSource); 45 | } 46 | 47 | /** 48 | * 创建基于Caffeine的Cache Manager 49 | * 50 | * @return 51 | */ 52 | @Bean("caffeineCacheManager") 53 | public CacheManager caffeineCacheManager() { 54 | CaffeineCacheManager caffeineCacheManager = new CaffeineCacheManager(); 55 | Caffeine