Repository: wuyouzhuguli/SpringAll Branch: master Commit: 614d2578d949 Files: 1050 Total size: 1.1 MB Directory structure: gitextract_zh464p81/ ├── .gitignore ├── 01.Start-Spring-Boot/ │ ├── pom.xml │ └── src/ │ ├── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── springboot/ │ │ │ └── demo/ │ │ │ └── DemoApplication.java │ │ └── resources/ │ │ └── application.properties │ └── test/ │ └── java/ │ └── com/ │ └── springboot/ │ └── demo/ │ └── DemoApplicationTests.java ├── 02.Spring-Boot-Config/ │ ├── pom.xml │ └── src/ │ ├── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── springboot/ │ │ │ ├── Application.java │ │ │ ├── bean/ │ │ │ │ ├── BlogProperties.java │ │ │ │ ├── ConfigBean.java │ │ │ │ └── TestConfigBean.java │ │ │ └── controller/ │ │ │ └── IndexController.java │ │ └── resources/ │ │ ├── application-dev.properties │ │ ├── application-prod.properties │ │ ├── application.properties │ │ ├── banner.txt │ │ └── test.properties │ └── test/ │ └── java/ │ └── com/ │ └── springboot/ │ └── demo/ │ └── DemoApplicationTests.java ├── 03.Spring-Boot-MyBatis/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── com/ │ │ └── springboot/ │ │ ├── Application.java │ │ ├── bean/ │ │ │ └── Student.java │ │ ├── controller/ │ │ │ └── TestController.java │ │ ├── mapper/ │ │ │ └── StudentMapper.java │ │ └── service/ │ │ ├── StudentService.java │ │ └── impl/ │ │ └── StudentServiceImp.java │ └── resources/ │ ├── application.yml │ └── init.sql ├── 04.Spring-Boot-JdbcTemplate/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── com/ │ │ └── springboot/ │ │ ├── Application.java │ │ ├── bean/ │ │ │ └── Student.java │ │ ├── controller/ │ │ │ └── TestController.java │ │ ├── dao/ │ │ │ ├── StudentDao.java │ │ │ └── impl/ │ │ │ └── StudentDaoImp.java │ │ ├── mapper/ │ │ │ └── StudentMapper.java │ │ └── service/ │ │ ├── StudentService.java │ │ └── impl/ │ │ └── StudentServiceImp.java │ └── resources/ │ ├── application.yml │ └── init.sql ├── 05.Spring-Boot-MyBatis-MultiDataSource/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── com/ │ │ └── springboot/ │ │ ├── Application.java │ │ ├── controller/ │ │ │ └── StudentController.java │ │ ├── datasource/ │ │ │ ├── MysqlDatasourceConfig.java │ │ │ └── OracleDatasourceConfig.java │ │ ├── mysqldao/ │ │ │ └── MysqlStudentMapper.java │ │ ├── oracledao/ │ │ │ └── OracleStudentMapper.java │ │ └── service/ │ │ ├── StudentService.java │ │ └── impl/ │ │ └── StudentServiceImp.java │ └── resources/ │ ├── application.yml │ ├── mapper/ │ │ ├── mysql/ │ │ │ └── MysqlStudentMapper.xml │ │ └── oracle/ │ │ └── OracleStudentMapper.xml │ ├── mysql_sql.sql │ └── oracle_sql.sql ├── 06.Spring-Boot-JdbcTemplate-MultiDataSource/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── com/ │ │ └── springboot/ │ │ ├── Application.java │ │ ├── controller/ │ │ │ └── StudentController.java │ │ ├── dao/ │ │ │ ├── MysqlStudentDao.java │ │ │ ├── OracleStudentDao.java │ │ │ └── impl/ │ │ │ ├── MysqlStudentDaoImp.java │ │ │ └── OracleStudentDaoImp.java │ │ ├── datasource/ │ │ │ └── DataSourceConfig.java │ │ └── service/ │ │ ├── StudentService.java │ │ └── impl/ │ │ └── StudentServiceImp.java │ └── resources/ │ ├── application.yml │ ├── mysql_sql.sql │ └── oracle_sql.sql ├── 07.Spring-Boot-AOP-Log/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── com/ │ │ └── springboot/ │ │ ├── Application.java │ │ ├── annotation/ │ │ │ └── Log.java │ │ ├── aspect/ │ │ │ └── LogAspect.java │ │ ├── controller/ │ │ │ └── TestController.java │ │ ├── dao/ │ │ │ ├── SysLogDao.java │ │ │ └── impl/ │ │ │ └── SysLogDaoImp.java │ │ ├── domain/ │ │ │ └── SysLog.java │ │ └── util/ │ │ ├── HttpContextUtils.java │ │ └── IPUtils.java │ └── resources/ │ ├── application.yml │ └── init.sql ├── 08.Spring-Boot-Thymeleaf/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── com/ │ │ └── springboot/ │ │ ├── Application.java │ │ ├── bean/ │ │ │ └── Account.java │ │ └── controller/ │ │ └── IndexController.java │ └── resources/ │ ├── application.properties │ ├── static/ │ │ └── css/ │ │ └── style.css │ └── templates/ │ └── account.html ├── 09.Spring-Boot-Redis-Cache/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── com/ │ │ └── springboot/ │ │ ├── Application.java │ │ ├── ApplicationTest.java │ │ ├── bean/ │ │ │ └── Student.java │ │ ├── config/ │ │ │ └── RedisConfig.java │ │ ├── mapper/ │ │ │ └── StudentMapper.java │ │ └── service/ │ │ ├── StudentService.java │ │ └── impl/ │ │ └── StudentServiceImpl.java │ └── resources/ │ ├── application.yml │ └── init.sql ├── 10.Spring-Boot-Ehcache-Cache/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── com/ │ │ └── springboot/ │ │ ├── Application.java │ │ ├── ApplicationTest.java │ │ ├── bean/ │ │ │ └── Student.java │ │ ├── mapper/ │ │ │ └── StudentMapper.java │ │ └── service/ │ │ ├── StudentService.java │ │ └── impl/ │ │ └── StudentServiceImpl.java │ └── resources/ │ ├── application.yml │ ├── ehcache.xml │ └── init.sql ├── 11.Spring-Boot-Shiro-Authentication/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── com/ │ │ └── springboot/ │ │ ├── Application.java │ │ ├── config/ │ │ │ └── ShiroConfig.java │ │ ├── controller/ │ │ │ └── LoginController.java │ │ ├── dao/ │ │ │ └── UserMapper.java │ │ ├── pojo/ │ │ │ ├── ResponseBo.java │ │ │ └── User.java │ │ ├── shiro/ │ │ │ └── ShiroRealm.java │ │ └── util/ │ │ └── MD5Utils.java │ └── resources/ │ ├── application.yml │ ├── init.sql │ ├── mapper/ │ │ └── UserMapper.xml │ ├── static/ │ │ └── css/ │ │ └── login.css │ └── templates/ │ ├── index.html │ └── login.html ├── 12.Spring-Boot-Shiro-RememberMe/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── com/ │ │ └── springboot/ │ │ ├── Application.java │ │ ├── config/ │ │ │ └── ShiroConfig.java │ │ ├── controller/ │ │ │ └── LoginController.java │ │ ├── dao/ │ │ │ └── UserMapper.java │ │ ├── pojo/ │ │ │ ├── ResponseBo.java │ │ │ └── User.java │ │ ├── shiro/ │ │ │ └── ShiroRealm.java │ │ └── util/ │ │ └── MD5Utils.java │ └── resources/ │ ├── application.yml │ ├── init.sql │ ├── mapper/ │ │ └── UserMapper.xml │ ├── static/ │ │ └── css/ │ │ └── login.css │ └── templates/ │ ├── index.html │ └── login.html ├── 13.Spring-Boot-Shiro-Authorization/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── com/ │ │ └── springboot/ │ │ ├── Application.java │ │ ├── config/ │ │ │ └── ShiroConfig.java │ │ ├── controller/ │ │ │ ├── LoginController.java │ │ │ └── UserController.java │ │ ├── dao/ │ │ │ ├── UserMapper.java │ │ │ ├── UserPermissionMapper.java │ │ │ └── UserRoleMapper.java │ │ ├── handler/ │ │ │ └── GlobalExceptionHandler.java │ │ ├── pojo/ │ │ │ ├── Permission.java │ │ │ ├── ResponseBo.java │ │ │ ├── Role.java │ │ │ └── User.java │ │ ├── shiro/ │ │ │ └── ShiroRealm.java │ │ └── util/ │ │ └── MD5Utils.java │ └── resources/ │ ├── application.yml │ ├── init.sql │ ├── mapper/ │ │ ├── UserMapper.xml │ │ ├── UserPermissionMapper.xml │ │ └── UserRoleMapper.xml │ ├── static/ │ │ └── css/ │ │ └── login.css │ └── templates/ │ ├── 403.html │ ├── index.html │ ├── login.html │ └── user.html ├── 14.Spring-Boot-Shiro-Redis/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── com/ │ │ └── springboot/ │ │ ├── Application.java │ │ ├── config/ │ │ │ └── ShiroConfig.java │ │ ├── controller/ │ │ │ ├── LoginController.java │ │ │ └── UserController.java │ │ ├── dao/ │ │ │ ├── UserMapper.java │ │ │ ├── UserPermissionMapper.java │ │ │ └── UserRoleMapper.java │ │ ├── handler/ │ │ │ └── GlobalExceptionHandler.java │ │ ├── pojo/ │ │ │ ├── Permission.java │ │ │ ├── ResponseBo.java │ │ │ ├── Role.java │ │ │ └── User.java │ │ ├── shiro/ │ │ │ └── ShiroRealm.java │ │ └── util/ │ │ └── MD5Utils.java │ └── resources/ │ ├── application.yml │ ├── init.sql │ ├── mapper/ │ │ ├── UserMapper.xml │ │ ├── UserPermissionMapper.xml │ │ └── UserRoleMapper.xml │ ├── static/ │ │ └── css/ │ │ └── login.css │ └── templates/ │ ├── 403.html │ ├── index.html │ ├── login.html │ └── user.html ├── 15.Spring-Boot-Shiro-Ehcache/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── com/ │ │ └── springboot/ │ │ ├── Application.java │ │ ├── config/ │ │ │ └── ShiroConfig.java │ │ ├── controller/ │ │ │ ├── LoginController.java │ │ │ └── UserController.java │ │ ├── dao/ │ │ │ ├── UserMapper.java │ │ │ ├── UserPermissionMapper.java │ │ │ └── UserRoleMapper.java │ │ ├── handler/ │ │ │ └── GlobalExceptionHandler.java │ │ ├── pojo/ │ │ │ ├── Permission.java │ │ │ ├── ResponseBo.java │ │ │ ├── Role.java │ │ │ └── User.java │ │ ├── shiro/ │ │ │ └── ShiroRealm.java │ │ └── util/ │ │ └── MD5Utils.java │ └── resources/ │ ├── application.yml │ ├── config/ │ │ └── shiro-ehcache.xml │ ├── init.sql │ ├── mapper/ │ │ ├── UserMapper.xml │ │ ├── UserPermissionMapper.xml │ │ └── UserRoleMapper.xml │ ├── static/ │ │ └── css/ │ │ └── login.css │ └── templates/ │ ├── 403.html │ ├── index.html │ ├── login.html │ └── user.html ├── 16.Spring-Boot-Shiro-Thymeleaf-Tag/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── com/ │ │ └── springboot/ │ │ ├── Application.java │ │ ├── config/ │ │ │ └── ShiroConfig.java │ │ ├── controller/ │ │ │ ├── LoginController.java │ │ │ └── UserController.java │ │ ├── dao/ │ │ │ ├── UserMapper.java │ │ │ ├── UserPermissionMapper.java │ │ │ └── UserRoleMapper.java │ │ ├── handler/ │ │ │ └── GlobalExceptionHandler.java │ │ ├── pojo/ │ │ │ ├── Permission.java │ │ │ ├── ResponseBo.java │ │ │ ├── Role.java │ │ │ └── User.java │ │ ├── shiro/ │ │ │ └── ShiroRealm.java │ │ └── util/ │ │ └── MD5Utils.java │ └── resources/ │ ├── application.yml │ ├── config/ │ │ └── shiro-ehcache.xml │ ├── init.sql │ ├── mapper/ │ │ ├── UserMapper.xml │ │ ├── UserPermissionMapper.xml │ │ └── UserRoleMapper.xml │ ├── static/ │ │ └── css/ │ │ └── login.css │ └── templates/ │ ├── 403.html │ ├── index.html │ ├── login.html │ └── user.html ├── 17.Spring-Boot-Shiro-Session/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── com/ │ │ └── springboot/ │ │ ├── Application.java │ │ ├── config/ │ │ │ └── ShiroConfig.java │ │ ├── controller/ │ │ │ ├── LoginController.java │ │ │ ├── SessionController.java │ │ │ └── UserController.java │ │ ├── dao/ │ │ │ ├── UserMapper.java │ │ │ ├── UserPermissionMapper.java │ │ │ └── UserRoleMapper.java │ │ ├── handler/ │ │ │ └── GlobalExceptionHandler.java │ │ ├── listener/ │ │ │ └── ShiroSessionListener.java │ │ ├── pojo/ │ │ │ ├── Permission.java │ │ │ ├── ResponseBo.java │ │ │ ├── Role.java │ │ │ ├── User.java │ │ │ └── UserOnline.java │ │ ├── service/ │ │ │ ├── SessionService.java │ │ │ └── impl/ │ │ │ └── SessionServiceImpl.java │ │ ├── shiro/ │ │ │ └── ShiroRealm.java │ │ └── util/ │ │ └── MD5Utils.java │ └── resources/ │ ├── application.yml │ ├── config/ │ │ └── shiro-ehcache.xml │ ├── init.sql │ ├── mapper/ │ │ ├── UserMapper.xml │ │ ├── UserPermissionMapper.xml │ │ └── UserRoleMapper.xml │ ├── static/ │ │ ├── css/ │ │ │ └── login.css │ │ └── js/ │ │ └── dateFormat.js │ └── templates/ │ ├── 403.html │ ├── index.html │ ├── login.html │ ├── online.html │ └── user.html ├── 18.Spring-Boot-Jackson/ │ ├── pom.xml │ └── src/ │ ├── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ ├── DemoApplication.java │ │ │ ├── config/ │ │ │ │ ├── JacksonConfig.java │ │ │ │ ├── UserDeserializer.java │ │ │ │ └── UserSerializer.java │ │ │ ├── controller/ │ │ │ │ └── TestJsonController.java │ │ │ └── pojo/ │ │ │ └── User.java │ │ └── resources/ │ │ └── application.properties │ └── test/ │ └── java/ │ └── com/ │ └── example/ │ └── demo/ │ └── DemoApplicationTests.java ├── 19.Spring-Boot-Testing/ │ ├── pom.xml │ └── src/ │ ├── main/ │ │ ├── java/ │ │ │ └── demo/ │ │ │ └── springboot/ │ │ │ └── test/ │ │ │ ├── TestApplication.java │ │ │ ├── config/ │ │ │ │ └── MyMapper.java │ │ │ ├── controller/ │ │ │ │ └── UserController.java │ │ │ ├── domain/ │ │ │ │ └── User.java │ │ │ ├── mapper/ │ │ │ │ ├── SeqenceMapper.java │ │ │ │ └── UserMapper.java │ │ │ └── service/ │ │ │ ├── IService.java │ │ │ ├── UserService.java │ │ │ └── impl/ │ │ │ ├── BaseService.java │ │ │ └── UserServiceImpl.java │ │ └── resources/ │ │ ├── application.yml │ │ ├── config/ │ │ │ └── mybatis-config.xml │ │ └── init.sql │ └── test/ │ └── java/ │ └── demo/ │ └── springboot/ │ └── test/ │ └── UserControllerTest.java ├── 20.Spring-Boot-Swagger2/ │ ├── pom.xml │ └── src/ │ ├── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ └── demo/ │ │ │ ├── DemoApplication.java │ │ │ ├── config/ │ │ │ │ ├── SwaggerConfig.java │ │ │ │ └── WebConfig.java │ │ │ ├── controller/ │ │ │ │ └── UserController.java │ │ │ └── domain/ │ │ │ └── User.java │ │ └── resources/ │ │ └── application.yml │ └── test/ │ └── java/ │ └── com/ │ └── example/ │ └── demo/ │ └── DemoApplicationTests.java ├── 21.Spring-Boot-Actuator/ │ ├── pom.xml │ └── src/ │ ├── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── springboot/ │ │ │ └── demo/ │ │ │ └── DemoApplication.java │ │ └── resources/ │ │ └── application.yml │ └── test/ │ └── java/ │ └── com/ │ └── springboot/ │ └── demo/ │ └── DemoApplicationTests.java ├── 22.Spring-Boot-Email/ │ ├── pom.xml │ └── src/ │ ├── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── springboot/ │ │ │ └── demo/ │ │ │ ├── DemoApplication.java │ │ │ └── controller/ │ │ │ └── EmailController.java │ │ └── resources/ │ │ ├── application.yml │ │ ├── static/ │ │ │ └── file/ │ │ │ └── 项目文档.docx │ │ └── templates/ │ │ └── emailTemplate.html │ └── test/ │ └── java/ │ └── com/ │ └── springboot/ │ └── demo/ │ └── DemoApplicationTests.java ├── 23.Spring-Boot-Admin/ │ ├── Spring Boot Admin Client/ │ │ ├── pom.xml │ │ └── src/ │ │ ├── main/ │ │ │ ├── java/ │ │ │ │ └── com/ │ │ │ │ └── example/ │ │ │ │ └── demo/ │ │ │ │ └── DemoApplication.java │ │ │ └── resources/ │ │ │ └── application.yml │ │ └── test/ │ │ └── java/ │ │ └── com/ │ │ └── example/ │ │ └── demo/ │ │ └── DemoApplicationTests.java │ └── Spring Boot Admin Server/ │ ├── pom.xml │ └── src/ │ ├── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ └── demo/ │ │ │ └── DemoApplication.java │ │ └── resources/ │ │ └── application.yml │ └── test/ │ └── java/ │ └── com/ │ └── example/ │ └── demo/ │ └── DemoApplicationTests.java ├── 24.Spring-Boot-Devtools/ │ ├── pom.xml │ └── src/ │ ├── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── springboot/ │ │ │ └── demo/ │ │ │ └── DemoApplication.java │ │ └── resources/ │ │ └── application.yml │ └── test/ │ └── java/ │ └── com/ │ └── springboot/ │ └── demo/ │ └── DemoApplicationTests.java ├── 25.Spring-Boot-Exception/ │ ├── pom.xml │ └── src/ │ ├── main/ │ │ ├── java/ │ │ │ └── cc/ │ │ │ └── mrbird/ │ │ │ ├── Application.java │ │ │ ├── controller/ │ │ │ │ └── UserController.java │ │ │ ├── exception/ │ │ │ │ └── UserNotExistException.java │ │ │ └── handler/ │ │ │ └── ControllerExceptionHandler.java │ │ └── resources/ │ │ ├── application.properties │ │ └── resources/ │ │ └── error/ │ │ └── 500.html │ └── test/ │ └── java/ │ └── cc/ │ └── mrbird/ │ └── cc/ │ └── mrbird/ │ └── demo/ │ └── ApplicationTests.java ├── 26.Spring-Boot-Filter-Interceptor/ │ ├── pom.xml │ └── src/ │ ├── main/ │ │ ├── java/ │ │ │ └── cc/ │ │ │ └── mrbird/ │ │ │ ├── Application.java │ │ │ ├── config/ │ │ │ │ └── WebConfig.java │ │ │ ├── controller/ │ │ │ │ └── UserController.java │ │ │ ├── filter/ │ │ │ │ └── TimeFilter.java │ │ │ └── interceptor/ │ │ │ └── TimeInterceptor.java │ │ └── resources/ │ │ ├── application.properties │ │ └── resources/ │ │ └── error/ │ │ └── 500.html │ └── test/ │ └── java/ │ └── cc/ │ └── mrbird/ │ └── cc/ │ └── mrbird/ │ └── demo/ │ └── ApplicationTests.java ├── 27.Spring-Boot-Mapper-PageHelper/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── com/ │ │ └── springboot/ │ │ ├── Application.java │ │ ├── ApplicationTest.java │ │ ├── bean/ │ │ │ └── User.java │ │ ├── config/ │ │ │ └── MyMapper.java │ │ ├── mapper/ │ │ │ ├── SeqenceMapper.java │ │ │ └── UserMapper.java │ │ └── service/ │ │ ├── IService.java │ │ ├── UserService.java │ │ └── impl/ │ │ ├── BaseService.java │ │ └── UserServiceImpl.java │ └── resources/ │ ├── application.yml │ ├── mapper/ │ │ └── UserMapper.xml │ └── mybatis-generator.xml ├── 28.Spring-Cloud-Eureka-Server-Discovery/ │ ├── Eureka-Client/ │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ └── demo/ │ │ │ ├── DemoApplication.java │ │ │ └── controller/ │ │ │ └── TestController.java │ │ └── resources/ │ │ └── application.yml │ ├── Eureka-Service/ │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ └── demo/ │ │ │ └── DemoApplication.java │ │ └── resources/ │ │ ├── application-peer1.yml │ │ ├── application-peer2.yml │ │ └── application.yml │ └── Server-Consumer/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── com/ │ │ └── example/ │ │ └── demo/ │ │ ├── DemoApplication.java │ │ └── controller/ │ │ └── TestController.java │ └── resources/ │ └── application.yml ├── 29.Spring-Cloud-Ribbon-LoadBalance/ │ ├── Eureka-Client/ │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ └── demo/ │ │ │ ├── DemoApplication.java │ │ │ ├── controller/ │ │ │ │ ├── TestController.java │ │ │ │ └── UserController.java │ │ │ └── domain/ │ │ │ └── User.java │ │ └── resources/ │ │ └── application.yml │ ├── Eureka-Service/ │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ └── demo/ │ │ │ └── DemoApplication.java │ │ └── resources/ │ │ ├── application-peer1.yml │ │ ├── application-peer2.yml │ │ └── application.yml │ └── Ribbon-Consumer/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── com/ │ │ └── example/ │ │ └── demo/ │ │ ├── DemoApplication.java │ │ ├── controller/ │ │ │ └── TestController.java │ │ └── domain/ │ │ └── User.java │ └── resources/ │ └── application.yml ├── 30.Spring-Cloud-Hystrix-Circuit-Breaker/ │ ├── Eureka-Client/ │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ └── demo/ │ │ │ ├── DemoApplication.java │ │ │ ├── controller/ │ │ │ │ ├── TestController.java │ │ │ │ └── UserController.java │ │ │ └── domain/ │ │ │ └── User.java │ │ └── resources/ │ │ └── application.yml │ ├── Eureka-Service/ │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ └── demo/ │ │ │ └── DemoApplication.java │ │ └── resources/ │ │ ├── application-peer1.yml │ │ ├── application-peer2.yml │ │ └── application.yml │ └── Ribbon-Consumer/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── com/ │ │ └── example/ │ │ └── demo/ │ │ ├── DemoApplication.java │ │ ├── Service/ │ │ │ └── UserService.java │ │ ├── controller/ │ │ │ └── TestController.java │ │ ├── domain/ │ │ │ └── User.java │ │ └── filter/ │ │ └── HystrixRequestContextServletFilter.java │ └── resources/ │ └── application.yml ├── 31.Spring-Cloud-Hystrix-Dashboard-Turbine/ │ ├── Eureka-Client/ │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ └── demo/ │ │ │ ├── DemoApplication.java │ │ │ ├── controller/ │ │ │ │ ├── TestController.java │ │ │ │ └── UserController.java │ │ │ └── domain/ │ │ │ └── User.java │ │ └── resources/ │ │ └── application.yml │ ├── Eureka-Service/ │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ └── demo/ │ │ │ └── DemoApplication.java │ │ └── resources/ │ │ ├── application-peer1.yml │ │ ├── application-peer2.yml │ │ └── application.yml │ ├── Hystrix-Dashboard/ │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ └── demo/ │ │ │ └── DemoApplication.java │ │ └── resources/ │ │ └── application.yml │ ├── Ribbon-Consumer/ │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ └── demo/ │ │ │ ├── DemoApplication.java │ │ │ ├── Service/ │ │ │ │ └── UserService.java │ │ │ ├── controller/ │ │ │ │ └── TestController.java │ │ │ ├── domain/ │ │ │ │ └── User.java │ │ │ └── filter/ │ │ │ └── HystrixRequestContextServletFilter.java │ │ └── resources/ │ │ └── application.yml │ └── Turbine/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── com/ │ │ └── example/ │ │ └── demo/ │ │ └── DemoApplication.java │ └── resources/ │ └── application.yml ├── 32.Spring-Cloud-Hystrix-Dashboard-Turbine-RabbitMQ/ │ ├── Eureka-Client/ │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ └── demo/ │ │ │ ├── DemoApplication.java │ │ │ ├── controller/ │ │ │ │ ├── TestController.java │ │ │ │ └── UserController.java │ │ │ └── domain/ │ │ │ └── User.java │ │ └── resources/ │ │ └── application.yml │ ├── Eureka-Service/ │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ └── demo/ │ │ │ └── DemoApplication.java │ │ └── resources/ │ │ ├── application-peer1.yml │ │ ├── application-peer2.yml │ │ └── application.yml │ ├── Hystrix-Dashboard/ │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ └── demo/ │ │ │ └── DemoApplication.java │ │ └── resources/ │ │ └── application.yml │ ├── Ribbon-Consumer/ │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ └── demo/ │ │ │ ├── DemoApplication.java │ │ │ ├── Service/ │ │ │ │ └── UserService.java │ │ │ ├── controller/ │ │ │ │ └── TestController.java │ │ │ ├── domain/ │ │ │ │ └── User.java │ │ │ └── filter/ │ │ │ └── HystrixRequestContextServletFilter.java │ │ └── resources/ │ │ └── application.yml │ └── Turbine-Stream/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── com/ │ │ └── example/ │ │ └── demo/ │ │ └── DemoApplication.java │ └── resources/ │ └── application.yml ├── 33.Spring-Cloud-Feign-Declarative-REST-Client/ │ ├── Eureka-Client/ │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ └── demo/ │ │ │ ├── DemoApplication.java │ │ │ ├── controller/ │ │ │ │ ├── TestController.java │ │ │ │ └── UserController.java │ │ │ └── domain/ │ │ │ └── User.java │ │ └── resources/ │ │ └── application.yml │ ├── Eureka-Service/ │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ └── demo/ │ │ │ └── DemoApplication.java │ │ └── resources/ │ │ ├── application-peer1.yml │ │ ├── application-peer2.yml │ │ └── application.yml │ └── Feign-Consumer/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── com/ │ │ └── example/ │ │ └── demo/ │ │ ├── DemoApplication.java │ │ ├── controller/ │ │ │ └── TestController.java │ │ ├── domain/ │ │ │ └── User.java │ │ └── service/ │ │ ├── UserService.java │ │ └── UserServiceFallback.java │ └── resources/ │ └── application.yml ├── 34.Start-Spring-Security/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── cc/ │ │ └── mrbird/ │ │ ├── SecurityApplication.java │ │ ├── security/ │ │ │ └── browser/ │ │ │ └── BrowserSecurityConfig.java │ │ └── web/ │ │ └── controller/ │ │ └── TestController.java │ └── resources/ │ └── application.yml ├── 35.Spring-Security-Authentication/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── cc/ │ │ └── mrbird/ │ │ ├── SecurityApplication.java │ │ ├── domain/ │ │ │ └── MyUser.java │ │ ├── handler/ │ │ │ ├── MyAuthenticationFailureHandler.java │ │ │ └── MyAuthenticationSucessHandler.java │ │ ├── security/ │ │ │ └── browser/ │ │ │ ├── BrowserSecurityConfig.java │ │ │ └── UserDetailService.java │ │ └── web/ │ │ └── controller/ │ │ ├── BrowserSecurityController.java │ │ └── TestController.java │ └── resources/ │ ├── application.yml │ └── resources/ │ ├── css/ │ │ └── login.css │ └── login.html ├── 36.Spring-Security-ValidateCode/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── cc/ │ │ └── mrbird/ │ │ ├── SecurityApplication.java │ │ ├── domain/ │ │ │ └── MyUser.java │ │ ├── handler/ │ │ │ ├── MyAuthenticationFailureHandler.java │ │ │ └── MyAuthenticationSucessHandler.java │ │ ├── security/ │ │ │ └── browser/ │ │ │ ├── BrowserSecurityConfig.java │ │ │ └── UserDetailService.java │ │ ├── validate/ │ │ │ └── code/ │ │ │ ├── ImageCode.java │ │ │ ├── ValidateCodeException.java │ │ │ └── ValidateCodeFilter.java │ │ └── web/ │ │ └── controller/ │ │ ├── BrowserSecurityController.java │ │ ├── TestController.java │ │ └── ValidateController.java │ └── resources/ │ ├── application.yml │ └── resources/ │ ├── css/ │ │ └── login.css │ └── login.html ├── 37.Spring-Security-RememberMe/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── cc/ │ │ └── mrbird/ │ │ ├── SecurityApplication.java │ │ ├── domain/ │ │ │ └── MyUser.java │ │ ├── handler/ │ │ │ ├── MyAuthenticationFailureHandler.java │ │ │ └── MyAuthenticationSucessHandler.java │ │ ├── security/ │ │ │ └── browser/ │ │ │ ├── BrowserSecurityConfig.java │ │ │ └── UserDetailService.java │ │ ├── validate/ │ │ │ └── code/ │ │ │ ├── ImageCode.java │ │ │ ├── ValidateCodeException.java │ │ │ └── ValidateCodeFilter.java │ │ └── web/ │ │ └── controller/ │ │ ├── BrowserSecurityController.java │ │ ├── TestController.java │ │ └── ValidateController.java │ └── resources/ │ ├── application.yml │ └── resources/ │ ├── css/ │ │ └── login.css │ └── login.html ├── 38.Spring-Security-SmsCode/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── cc/ │ │ └── mrbird/ │ │ ├── SecurityApplication.java │ │ ├── domain/ │ │ │ └── MyUser.java │ │ ├── handler/ │ │ │ ├── MyAuthenticationFailureHandler.java │ │ │ └── MyAuthenticationSucessHandler.java │ │ ├── security/ │ │ │ └── browser/ │ │ │ ├── BrowserSecurityConfig.java │ │ │ └── UserDetailService.java │ │ ├── validate/ │ │ │ ├── code/ │ │ │ │ ├── ImageCode.java │ │ │ │ ├── ValidateCodeException.java │ │ │ │ └── ValidateCodeFilter.java │ │ │ └── smscode/ │ │ │ ├── SmsAuthenticationConfig.java │ │ │ ├── SmsAuthenticationFilter.java │ │ │ ├── SmsAuthenticationProvider.java │ │ │ ├── SmsAuthenticationToken.java │ │ │ ├── SmsCode.java │ │ │ └── SmsCodeFilter.java │ │ └── web/ │ │ └── controller/ │ │ ├── BrowserSecurityController.java │ │ ├── TestController.java │ │ └── ValidateController.java │ └── resources/ │ ├── application.yml │ └── resources/ │ ├── css/ │ │ └── login.css │ └── login.html ├── 39.Spring-Cloud-Zuul-Router/ │ ├── Eureka-Client/ │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ └── demo/ │ │ │ ├── DemoApplication.java │ │ │ ├── controller/ │ │ │ │ ├── TestController.java │ │ │ │ └── UserController.java │ │ │ └── domain/ │ │ │ └── User.java │ │ └── resources/ │ │ └── application.yml │ ├── Eureka-Service/ │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ └── demo/ │ │ │ └── DemoApplication.java │ │ └── resources/ │ │ ├── application-peer1.yml │ │ ├── application-peer2.yml │ │ └── application.yml │ ├── Feign-Consumer/ │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ └── demo/ │ │ │ ├── DemoApplication.java │ │ │ ├── controller/ │ │ │ │ └── TestController.java │ │ │ ├── domain/ │ │ │ │ └── User.java │ │ │ └── service/ │ │ │ ├── UserService.java │ │ │ └── UserServiceFallback.java │ │ └── resources/ │ │ └── application.yml │ └── Zuul-Gateway/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── com/ │ │ └── example/ │ │ └── demo/ │ │ ├── DemoApplication.java │ │ └── filter/ │ │ └── PreSendForwardFilter.java │ └── resources/ │ └── application.yml ├── 40.Spring-Boot-Dubbo-Zookeeper/ │ ├── common-api/ │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── cc/ │ │ └── mrbird/ │ │ └── common/ │ │ └── api/ │ │ └── HelloService.java │ ├── pom.xml │ ├── server-consumer/ │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ ├── java/ │ │ │ └── cc/ │ │ │ └── mrbird/ │ │ │ ├── ConsumerApplicaiton.java │ │ │ └── consumer/ │ │ │ └── controller/ │ │ │ └── HelloController.java │ │ └── resources/ │ │ └── application.yml │ └── server-provider/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── cc/ │ │ └── mrbird/ │ │ ├── ProviderApplicaiton.java │ │ └── provider/ │ │ └── service/ │ │ └── HelloServiceImpl.java │ └── resources/ │ └── application.yml ├── 41.Spring-Cloud-Config/ │ ├── Eureka-Service/ │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ └── demo/ │ │ │ └── DemoApplication.java │ │ └── resources/ │ │ ├── application-peer1.yml │ │ ├── application-peer2.yml │ │ └── application.yml │ ├── config-client/ │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ ├── java/ │ │ │ └── cc/ │ │ │ └── mrbird/ │ │ │ └── demo/ │ │ │ ├── DemoApplication.java │ │ │ └── controller/ │ │ │ └── TestController.java │ │ └── resources/ │ │ └── bootstrap.yml │ ├── config-server/ │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ ├── java/ │ │ │ └── cc/ │ │ │ └── mrbird/ │ │ │ └── demo/ │ │ │ └── DemoApplication.java │ │ └── resources/ │ │ ├── application.yml │ │ ├── bootstrap.yml │ │ └── config-server.keystore │ └── properties/ │ ├── febs-dev.yml │ ├── febs-pro.yml │ ├── febs-test.yml │ └── febs.yml ├── 42.Spring-Cloud-Bus/ │ ├── Eureka-Service/ │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ └── demo/ │ │ │ └── DemoApplication.java │ │ └── resources/ │ │ ├── application-peer1.yml │ │ ├── application-peer2.yml │ │ └── application.yml │ ├── config-client/ │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ ├── java/ │ │ │ └── cc/ │ │ │ └── mrbird/ │ │ │ └── demo/ │ │ │ ├── DemoApplication.java │ │ │ └── controller/ │ │ │ └── TestController.java │ │ └── resources/ │ │ └── bootstrap.yml │ └── config-server/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── cc/ │ │ └── mrbird/ │ │ └── demo/ │ │ └── DemoApplication.java │ └── resources/ │ ├── application.yml │ ├── bootstrap.yml │ └── config-server.keystore ├── 43.Spring-Cloud-Sleuth/ │ ├── Eureka-Service/ │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ └── demo/ │ │ │ └── DemoApplication.java │ │ └── resources/ │ │ ├── application-peer1.yml │ │ ├── application-peer2.yml │ │ └── application.yml │ ├── Server-Provider1/ │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ └── demo/ │ │ │ ├── DemoApplication.java │ │ │ └── controller/ │ │ │ └── HelloController.java │ │ └── resources/ │ │ └── application.yml │ ├── Server-Provider2/ │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ └── demo/ │ │ │ ├── DemoApplication.java │ │ │ └── controller/ │ │ │ └── HelloController.java │ │ └── resources/ │ │ └── application.yml │ └── Zipkin-Server/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── com/ │ │ └── example/ │ │ └── demo/ │ │ └── DemoApplication.java │ └── resources/ │ └── application.yml ├── 44.Spring-Boot-Autoconfiguration/ │ ├── pom.xml │ └── src/ │ ├── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ └── demo/ │ │ │ ├── DemoApplication.java │ │ │ ├── annotation/ │ │ │ │ ├── EnableHelloWorld.java │ │ │ │ ├── FirstLevelService.java │ │ │ │ └── SecondLevelService.java │ │ │ ├── bootstrap/ │ │ │ │ ├── EnableAutoConfigurationBootstrap.java │ │ │ │ ├── ServiceBootstrap.java │ │ │ │ └── TestEnableBootstap.java │ │ │ ├── configuration/ │ │ │ │ ├── HelloWorldAutoConfiguration.java │ │ │ │ └── HelloWorldConfiguration.java │ │ │ ├── selector/ │ │ │ │ └── HelloWorldImportSelector.java │ │ │ └── service/ │ │ │ └── TestService.java │ │ └── resources/ │ │ ├── META-INF/ │ │ │ └── spring.factories │ │ └── application.properties │ └── test/ │ └── java/ │ └── com/ │ └── example/ │ └── demo/ │ └── DemoApplicationTests.java ├── 45.Spring-Boot-SpringApplication/ │ ├── pom.xml │ └── src/ │ ├── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ └── demo/ │ │ │ ├── DemoApplication.java │ │ │ ├── initializer/ │ │ │ │ ├── AfterHelloApplicationContextInitializer.java │ │ │ │ └── HelloApplicationContextInitializer.java │ │ │ ├── listener/ │ │ │ │ ├── AfterContextClosedEventListener.java │ │ │ │ ├── ContextClosedEventListener.java │ │ │ │ └── HelloApplicationRunListener.java │ │ │ └── runner/ │ │ │ ├── HelloApplicationRunner.java │ │ │ └── HelloCommandLineRunner.java │ │ └── resources/ │ │ ├── META-INF/ │ │ │ └── spring.factories │ │ └── application.properties │ └── test/ │ └── java/ │ └── com/ │ └── example/ │ └── demo/ │ └── DemoApplicationTests.java ├── 46.Spring-Boot-Hibernate-Validator/ │ ├── pom.xml │ └── src/ │ ├── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ └── demo/ │ │ │ ├── DemoApplication.java │ │ │ ├── controller/ │ │ │ │ └── TestController.java │ │ │ ├── domain/ │ │ │ │ └── User.java │ │ │ └── handler/ │ │ │ └── GlobalExceptionHandler.java │ │ └── resources/ │ │ ├── ValidationMessages.properties │ │ └── application.properties │ └── test/ │ └── java/ │ └── com/ │ └── example/ │ └── demo/ │ └── DemoApplicationTests.java ├── 47.Spring-Boot-Content-Negotiation/ │ ├── pom.xml │ └── src/ │ ├── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ └── demo/ │ │ │ ├── DemoApplication.java │ │ │ ├── config/ │ │ │ │ └── WebConfigurer.java │ │ │ ├── controller/ │ │ │ │ └── TestController.java │ │ │ ├── converter/ │ │ │ │ └── PropertiesHttpMessageConverter.java │ │ │ ├── handler/ │ │ │ │ └── PropertiesHandlerMethodReturnValueHandler.java │ │ │ └── resolver/ │ │ │ └── PropertiesHandlerMethodArgumentResolver.java │ │ └── resources/ │ │ └── application.properties │ └── test/ │ └── java/ │ └── com/ │ └── example/ │ └── demo/ │ └── DemoApplicationTests.java ├── 48.Spring-Boot-CORS-Support/ │ ├── pom.xml │ └── src/ │ ├── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ └── demo/ │ │ │ ├── DemoApplication.java │ │ │ ├── config/ │ │ │ │ └── WebConfigurer.java │ │ │ └── controller/ │ │ │ └── TestController.java │ │ └── resources/ │ │ ├── application.properties │ │ └── templates/ │ │ └── index.html │ └── test/ │ └── java/ │ └── com/ │ └── example/ │ └── demo/ │ └── DemoApplicationTests.java ├── 49.Spring-Boot-Async/ │ ├── pom.xml │ └── src/ │ ├── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ └── demo/ │ │ │ ├── DemoApplication.java │ │ │ ├── config/ │ │ │ │ └── AsyncPoolConfig.java │ │ │ ├── controller/ │ │ │ │ └── TestController.java │ │ │ └── service/ │ │ │ └── TestService.java │ │ └── resources/ │ │ └── application.properties │ └── test/ │ └── java/ │ └── com/ │ └── example/ │ └── demo/ │ └── DemoApplicationTests.java ├── 50.Spring-Regist-Bean/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── cc/ │ │ └── mrbird/ │ │ ├── DemoApplication.java │ │ └── demo/ │ │ ├── condition/ │ │ │ └── MyCondition.java │ │ ├── config/ │ │ │ └── WebConfig.java │ │ ├── controller/ │ │ │ └── UserController.java │ │ ├── dao/ │ │ │ └── UserMapper.java │ │ ├── domain/ │ │ │ ├── Apple.java │ │ │ ├── Banana.java │ │ │ ├── Cherry.java │ │ │ ├── Hello.java │ │ │ ├── Strawberry.java │ │ │ ├── User.java │ │ │ ├── UserDetail.java │ │ │ └── Watermelon.java │ │ ├── factory/ │ │ │ └── CherryFactoryBean.java │ │ ├── filter/ │ │ │ └── MyTypeFilter.java │ │ ├── register/ │ │ │ └── MyImportBeanDefinitionRegistrar.java │ │ ├── selector/ │ │ │ └── MyImportSelector.java │ │ └── service/ │ │ ├── CalculateService.java │ │ ├── UserService.java │ │ └── impl/ │ │ ├── Java7CalculateServiceImpl.java │ │ └── Java8CalculateServiceImpl.java │ └── resources/ │ └── application.properties ├── 51.Spring-Bean-Lifecycle/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── cc/ │ │ └── mrbird/ │ │ ├── DemoApplication.java │ │ └── demo/ │ │ ├── config/ │ │ │ ├── MyBeanPostProcessor.java │ │ │ └── WebConfig.java │ │ └── domain/ │ │ ├── Bird.java │ │ ├── Fish.java │ │ └── User.java │ └── resources/ │ └── application.properties ├── 52.Dubbo-OPS-Mointor/ │ └── spring-boot-dubbo-applicaiton/ │ ├── common-api/ │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── cc/ │ │ └── mrbird/ │ │ └── common/ │ │ └── api/ │ │ └── HelloService.java │ ├── pom.xml │ ├── server-consumer/ │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ ├── java/ │ │ │ └── cc/ │ │ │ └── mrbird/ │ │ │ ├── ConsumerApplicaiton.java │ │ │ └── consumer/ │ │ │ └── controller/ │ │ │ └── HelloController.java │ │ └── resources/ │ │ └── application.yml │ └── server-provider/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── cc/ │ │ └── mrbird/ │ │ ├── ProviderApplicaiton.java │ │ └── provider/ │ │ └── service/ │ │ └── HelloServiceImpl.java │ └── resources/ │ └── application.yml ├── 53.Dubbo-High-Availability/ │ ├── common-api/ │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── cc/ │ │ └── mrbird/ │ │ └── common/ │ │ └── api/ │ │ └── HelloService.java │ ├── pom.xml │ ├── server-consumer/ │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ ├── java/ │ │ │ └── cc/ │ │ │ └── mrbird/ │ │ │ ├── ConsumerApplicaiton.java │ │ │ └── consumer/ │ │ │ └── controller/ │ │ │ └── HelloController.java │ │ └── resources/ │ │ └── application.yml │ └── server-provider/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── cc/ │ │ └── mrbird/ │ │ ├── ProviderApplicaiton.java │ │ └── provider/ │ │ └── service/ │ │ └── HelloServiceImpl.java │ └── resources/ │ └── application.yml ├── 54.Spring-Boot-Kafka/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── com/ │ │ └── example/ │ │ └── demo/ │ │ ├── KafkaApplication.java │ │ ├── config/ │ │ │ ├── KafkaConsumerConfig.java │ │ │ └── KafkaProducerConfig.java │ │ ├── controller/ │ │ │ └── SendMessageController.java │ │ ├── domain/ │ │ │ └── Message.java │ │ └── listener/ │ │ └── KafkaMessageListener.java │ └── resources/ │ └── application.yml ├── 55.Spring-Cloud-Consul/ │ ├── server-consumer/ │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ └── demo/ │ │ │ ├── ServerConsumerApplication.java │ │ │ └── TestController.java │ │ └── resources/ │ │ └── application.yml │ └── server-proivder/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── com/ │ │ └── example/ │ │ └── demo/ │ │ ├── ServerProviderApplication.java │ │ └── TestController.java │ └── resources/ │ └── application.yml ├── 56.Spring-Boot-MongoDB-crud/ │ ├── Mongo DB crud.postman_collection.json │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── com/ │ │ └── example/ │ │ └── mongodb/ │ │ ├── MongodbApplication.java │ │ ├── controller/ │ │ │ └── UserController.java │ │ ├── dao/ │ │ │ └── UserDao.java │ │ ├── domain/ │ │ │ └── User.java │ │ └── service/ │ │ └── UserService.java │ └── resources/ │ └── application.yml ├── 57.Spring-Boot-WebFlux/ │ ├── async-servlet/ │ │ ├── src/ │ │ │ ├── AsyncServlet.java │ │ │ └── SyncServlet.java │ │ └── web/ │ │ ├── WEB-INF/ │ │ │ └── web.xml │ │ └── index.html │ └── webflux/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── com/ │ │ └── example/ │ │ └── webflux/ │ │ ├── FluxTest.java │ │ ├── MonoFluxTest.java │ │ ├── MonoTest.java │ │ ├── TestController.java │ │ ├── ViewController.java │ │ └── WebfluxApplication.java │ └── resources/ │ ├── application.yml │ └── templates/ │ └── flux.html ├── 58.Spring-Boot-WebFlux-crud/ │ ├── pom.xml │ ├── src/ │ │ └── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ └── webflux/ │ │ │ ├── WebfluxApplication.java │ │ │ ├── controller/ │ │ │ │ └── UserController.java │ │ │ ├── dao/ │ │ │ │ └── UserDao.java │ │ │ ├── domain/ │ │ │ │ └── User.java │ │ │ └── service/ │ │ │ └── UserService.java │ │ └── resources/ │ │ └── application.yml │ └── webflux crud.postman_collection.json ├── 59.Spring-Security-SessionManager/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── cc/ │ │ └── mrbird/ │ │ ├── SecurityApplication.java │ │ ├── domain/ │ │ │ └── MyUser.java │ │ ├── handler/ │ │ │ ├── MyAuthenticationFailureHandler.java │ │ │ └── MyAuthenticationSucessHandler.java │ │ ├── security/ │ │ │ └── browser/ │ │ │ ├── BrowserSecurityConfig.java │ │ │ └── UserDetailService.java │ │ ├── session/ │ │ │ └── MySessionExpiredStrategy.java │ │ ├── validate/ │ │ │ ├── code/ │ │ │ │ ├── ImageCode.java │ │ │ │ ├── ValidateCodeException.java │ │ │ │ └── ValidateCodeFilter.java │ │ │ └── smscode/ │ │ │ ├── SmsAuthenticationConfig.java │ │ │ ├── SmsAuthenticationFilter.java │ │ │ ├── SmsAuthenticationProvider.java │ │ │ ├── SmsAuthenticationToken.java │ │ │ ├── SmsCode.java │ │ │ └── SmsCodeFilter.java │ │ └── web/ │ │ └── controller/ │ │ ├── BrowserSecurityController.java │ │ ├── TestController.java │ │ └── ValidateController.java │ └── resources/ │ ├── application.yml │ └── resources/ │ ├── css/ │ │ └── login.css │ └── login.html ├── 60.Spring-Security-Logout/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── cc/ │ │ └── mrbird/ │ │ ├── SecurityApplication.java │ │ ├── domain/ │ │ │ └── MyUser.java │ │ ├── handler/ │ │ │ ├── MyAuthenticationFailureHandler.java │ │ │ ├── MyAuthenticationSucessHandler.java │ │ │ └── MyLogOutSuccessHandler.java │ │ ├── security/ │ │ │ └── browser/ │ │ │ ├── BrowserSecurityConfig.java │ │ │ └── UserDetailService.java │ │ ├── session/ │ │ │ └── MySessionExpiredStrategy.java │ │ ├── validate/ │ │ │ ├── code/ │ │ │ │ ├── ImageCode.java │ │ │ │ ├── ValidateCodeException.java │ │ │ │ └── ValidateCodeFilter.java │ │ │ └── smscode/ │ │ │ ├── SmsAuthenticationConfig.java │ │ │ ├── SmsAuthenticationFilter.java │ │ │ ├── SmsAuthenticationProvider.java │ │ │ ├── SmsAuthenticationToken.java │ │ │ ├── SmsCode.java │ │ │ └── SmsCodeFilter.java │ │ └── web/ │ │ └── controller/ │ │ ├── BrowserSecurityController.java │ │ ├── TestController.java │ │ └── ValidateController.java │ └── resources/ │ ├── application.yml │ └── resources/ │ ├── css/ │ │ └── login.css │ └── login.html ├── 61.Spring-security-Permission/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── cc/ │ │ └── mrbird/ │ │ ├── SecurityApplication.java │ │ ├── domain/ │ │ │ └── MyUser.java │ │ ├── handler/ │ │ │ ├── MyAuthenticationAccessDeniedHandler.java │ │ │ ├── MyAuthenticationFailureHandler.java │ │ │ ├── MyAuthenticationSucessHandler.java │ │ │ └── MyLogOutSuccessHandler.java │ │ ├── security/ │ │ │ └── browser/ │ │ │ ├── BrowserSecurityConfig.java │ │ │ └── UserDetailService.java │ │ ├── session/ │ │ │ └── MySessionExpiredStrategy.java │ │ ├── validate/ │ │ │ ├── code/ │ │ │ │ ├── ImageCode.java │ │ │ │ ├── ValidateCodeException.java │ │ │ │ └── ValidateCodeFilter.java │ │ │ └── smscode/ │ │ │ ├── SmsAuthenticationConfig.java │ │ │ ├── SmsAuthenticationFilter.java │ │ │ ├── SmsAuthenticationProvider.java │ │ │ ├── SmsAuthenticationToken.java │ │ │ ├── SmsCode.java │ │ │ └── SmsCodeFilter.java │ │ └── web/ │ │ └── controller/ │ │ ├── BrowserSecurityController.java │ │ ├── TestController.java │ │ └── ValidateController.java │ └── resources/ │ ├── application.yml │ └── resources/ │ ├── css/ │ │ └── login.css │ └── login.html ├── 62.Spring-Boot-Shiro-JWT/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── com/ │ │ └── example/ │ │ └── demo/ │ │ ├── DemoApplication.java │ │ ├── authentication/ │ │ │ ├── JWTFilter.java │ │ │ ├── JWTToken.java │ │ │ ├── JWTUtil.java │ │ │ ├── ShiroConfig.java │ │ │ └── ShiroRealm.java │ │ ├── controller/ │ │ │ ├── LoginController.java │ │ │ └── TestController.java │ │ ├── domain/ │ │ │ ├── Response.java │ │ │ └── User.java │ │ ├── exception/ │ │ │ └── SystemException.java │ │ ├── handler/ │ │ │ └── GlobalExceptionHandler.java │ │ ├── properties/ │ │ │ └── SystemProperties.java │ │ ├── runner/ │ │ │ └── PrintRunner.java │ │ └── utils/ │ │ ├── DateUtil.java │ │ ├── MD5Util.java │ │ ├── SpringContextUtil.java │ │ └── SystemUtils.java │ └── resources/ │ ├── ValidationMessages.properties │ ├── application.yml │ ├── postman.json │ └── readme.md ├── 63.Spring-Security-OAuth2-Guide/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── cc/ │ │ └── mrbird/ │ │ └── security/ │ │ ├── SecurityApplication.java │ │ ├── config/ │ │ │ ├── AuthorizationServerConfig.java │ │ │ └── ResourceServerConfig.java │ │ ├── controller/ │ │ │ └── UserController.java │ │ ├── domain/ │ │ │ └── MyUser.java │ │ └── service/ │ │ └── UserDetailService.java │ └── resources/ │ └── application.yml ├── 64.Spring-Security-OAuth2-Customize/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── cc/ │ │ └── mrbird/ │ │ └── security/ │ │ ├── SecurityApplication.java │ │ ├── config/ │ │ │ ├── AuthorizationServerConfig.java │ │ │ └── ResourceServerConfig.java │ │ ├── controller/ │ │ │ ├── UserController.java │ │ │ └── ValidateController.java │ │ ├── domain/ │ │ │ └── MyUser.java │ │ ├── handler/ │ │ │ ├── MyAuthenticationFailureHandler.java │ │ │ └── MyAuthenticationSucessHandler.java │ │ ├── service/ │ │ │ ├── RedisCodeService.java │ │ │ └── UserDetailService.java │ │ └── validate/ │ │ └── smscode/ │ │ ├── SmsAuthenticationConfig.java │ │ ├── SmsAuthenticationFilter.java │ │ ├── SmsAuthenticationProvider.java │ │ ├── SmsAuthenticationToken.java │ │ ├── SmsCode.java │ │ └── SmsCodeFilter.java │ └── resources/ │ └── application.yml ├── 65.Spring-Security-OAuth2-Config/ │ ├── pom.xml │ ├── security.postman_collection.json │ └── src/ │ └── main/ │ ├── java/ │ │ └── cc/ │ │ └── mrbird/ │ │ └── security/ │ │ ├── SecurityApplication.java │ │ ├── config/ │ │ │ ├── AuthorizationServerConfig.java │ │ │ ├── JWTokenConfig.java │ │ │ ├── ResourceServerConfig.java │ │ │ ├── SecurityConfig.java │ │ │ └── TokenStoreConfig.java │ │ ├── controller/ │ │ │ ├── UserController.java │ │ │ └── ValidateController.java │ │ ├── domain/ │ │ │ └── MyUser.java │ │ ├── enhancer/ │ │ │ └── JWTokenEnhancer.java │ │ ├── handler/ │ │ │ ├── MyAuthenticationFailureHandler.java │ │ │ └── MyAuthenticationSucessHandler.java │ │ ├── service/ │ │ │ ├── RedisCodeService.java │ │ │ └── UserDetailService.java │ │ └── validate/ │ │ └── smscode/ │ │ ├── SmsAuthenticationConfig.java │ │ ├── SmsAuthenticationFilter.java │ │ ├── SmsAuthenticationProvider.java │ │ ├── SmsAuthenticationToken.java │ │ ├── SmsCode.java │ │ └── SmsCodeFilter.java │ └── resources/ │ └── application.yml ├── 66.Spring-Security-OAuth2-SSO/ │ ├── pom.xml │ ├── sso-application-one/ │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ ├── java/ │ │ │ └── cc/ │ │ │ └── mrbird/ │ │ │ └── sso/ │ │ │ ├── SsoApplicaitonOne.java │ │ │ └── client/ │ │ │ ├── config/ │ │ │ │ └── WebSecurityConfigurer.java │ │ │ └── controller/ │ │ │ └── UserController.java │ │ └── resources/ │ │ ├── application.yml │ │ └── static/ │ │ └── index.html │ ├── sso-application-two/ │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ ├── java/ │ │ │ └── cc/ │ │ │ └── mrbird/ │ │ │ └── sso/ │ │ │ ├── SsoApplicaitonTwo.java │ │ │ └── client/ │ │ │ └── controller/ │ │ │ └── UserController.java │ │ └── resources/ │ │ ├── application.yml │ │ └── static/ │ │ └── index.html │ └── sso-server/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── cc/ │ │ └── mrbird/ │ │ └── sso/ │ │ ├── SsoServerApplication.java │ │ └── server/ │ │ ├── config/ │ │ │ ├── SsoAuthorizationServerConfig.java │ │ │ └── WebSecurityConfig.java │ │ ├── domain/ │ │ │ └── MyUser.java │ │ └── service/ │ │ └── UserDetailService.java │ └── resources/ │ └── application.yml ├── 67.spring-batch-start/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── cc/ │ │ └── mrbird/ │ │ └── batch/ │ │ ├── SpringBatchStartApplication.java │ │ ├── decider/ │ │ │ └── MyDecider.java │ │ └── job/ │ │ ├── DeciderJobDemo.java │ │ ├── FirstJobDemo.java │ │ ├── FlowJobDemo.java │ │ ├── MultiStepJobDemo.java │ │ ├── NestedJobDemo.java │ │ └── SplitJobDemo.java │ └── resources/ │ └── application.yml ├── 68.spring-batch-itemreader/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── cc/ │ │ └── mrbird/ │ │ └── batch/ │ │ ├── SpringBatchItemreaderApplication.java │ │ ├── entity/ │ │ │ └── TestData.java │ │ ├── job/ │ │ │ ├── DataSourceItemReaderDemo.java │ │ │ ├── FileItemReaderDemo.java │ │ │ ├── JSONFileItemReaderDemo.java │ │ │ ├── MultiFileIteamReaderDemo.java │ │ │ ├── MySimpleItemReaderDemo.java │ │ │ └── XmlFileItemReaderDemo.java │ │ └── reader/ │ │ └── MySimpleIteamReader.java │ └── resources/ │ ├── TEST.sql │ ├── application.yml │ ├── file │ ├── file.json │ ├── file.xml │ ├── file1 │ └── file2 ├── 69.spring-batch-itemwriter/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── cc/ │ │ └── mrbird/ │ │ └── batch/ │ │ ├── SpringBatchItemwriterApplication.java │ │ ├── entity/ │ │ │ └── TestData.java │ │ ├── job/ │ │ │ ├── DatabaseItemWriterDemo.java │ │ │ ├── FileItemWriterDemo.java │ │ │ ├── JsonFileItemWriterDemo.java │ │ │ ├── MultiFileItemWriteDemo.java │ │ │ └── XmlFileItemWriterDemo.java │ │ ├── reader/ │ │ │ └── ItemReaderConfigure.java │ │ └── writer/ │ │ └── ItemWriterConfigure.java │ └── resources/ │ └── application.yml ├── 70.spring-batch-itemprocessor/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── cc/ │ │ └── mrbird/ │ │ └── batch/ │ │ ├── SpringBatchItemprocessorApplication.java │ │ ├── entity/ │ │ │ ├── TestData.java │ │ │ ├── job/ │ │ │ │ ├── BeanValidatingItemProcessorDemo.java │ │ │ │ ├── CompositeItemProcessorDemo.java │ │ │ │ ├── TestDataFilterItemProcessorDemo.java │ │ │ │ ├── TestDataTransformItemPorcessorDemo.java │ │ │ │ └── ValidatingItemProcessorDemo.java │ │ │ └── reader/ │ │ │ └── ItemReaderConfigure.java │ │ └── processor/ │ │ ├── TestDataFilterItemProcessor.java │ │ └── TestDataTransformItemPorcessor.java │ └── resources/ │ └── application.yml ├── 71.spring-batch-listener/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── cc/ │ │ └── mrbird/ │ │ └── batch/ │ │ ├── SpringBatchListenerApplication.java │ │ ├── job/ │ │ │ ├── CompositeJobExecutionListenerJobDemo.java │ │ │ └── ListenerTestJobDemo.java │ │ └── listener/ │ │ ├── MyChunkListener.java │ │ ├── MyItemProcessListener.java │ │ ├── MyItemReaderListener.java │ │ ├── MyItemWriterListener.java │ │ ├── MyJobExecutionListener.java │ │ └── MyStepExecutionListener.java │ └── resources/ │ └── application.yml ├── 72.spring-batch-exception/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── cc/ │ │ └── mrbird/ │ │ └── batch/ │ │ ├── SpringBatchExceptionApplication.java │ │ ├── exception/ │ │ │ └── MyJobExecutionException.java │ │ ├── job/ │ │ │ ├── DefaultExceptionJobDemo.java │ │ │ ├── RestartJobDemo.java │ │ │ ├── RetryExceptionJobDemo.java │ │ │ ├── SkipExceptionJobDemo.java │ │ │ └── TransactionJobDemo.java │ │ └── listener/ │ │ └── MySkipListener.java │ └── resources/ │ └── application.yml ├── 73.spring-batch-launcher/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── cc/ │ │ └── mrbird/ │ │ └── batch/ │ │ ├── SpringBatchLauncherApplication.java │ │ ├── configure/ │ │ │ └── JobConfigure.java │ │ ├── controller/ │ │ │ └── JobController.java │ │ └── job/ │ │ └── MyJob.java │ └── resources/ │ └── application.yml ├── 74.spring-cloud-alibaba-nacos-register/ │ ├── consumer/ │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ ├── java/ │ │ │ └── cc/ │ │ │ └── mrbird/ │ │ │ └── consumer/ │ │ │ ├── ConsumerApplication.java │ │ │ ├── configure/ │ │ │ │ └── ConsumerConfigure.java │ │ │ └── controller/ │ │ │ └── ConsumeController.java │ │ └── resources/ │ │ └── application.yml │ ├── pom.xml │ └── provider/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── cc/ │ │ └── mrbird/ │ │ └── provider/ │ │ ├── ProviderApplication.java │ │ └── controller/ │ │ └── HelloController.java │ └── resources/ │ └── application.yml ├── 75.spring-cloud-alibaba-nacos-config/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── cc/ │ │ └── mrbird/ │ │ └── nacos/ │ │ ├── SpringCloudAlibabaNacosConfigApplication.java │ │ └── controller/ │ │ └── TestController.java │ └── resources/ │ ├── application.yml │ └── bootstrap.yml ├── 76.spring-boot-websocket-socketjs/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── cc/ │ │ └── mrbird/ │ │ └── socket/ │ │ ├── SpringBootWebsocketSocketjsApplication.java │ │ ├── configure/ │ │ │ └── WebSocketServerConfigure.java │ │ └── handler/ │ │ └── MyStringWebSocketHandler.java │ └── resources/ │ ├── application.properties │ └── static/ │ └── client.html ├── 77.spring-cloud-alibaba-sentinel-dashboard-guide/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── cc/ │ │ └── mrbird/ │ │ └── sentinel/ │ │ ├── SpringCloudAlibabaSentinelFlowControlApplication.java │ │ ├── controller/ │ │ │ └── TestController.java │ │ └── service/ │ │ └── HelloService.java │ └── resources/ │ └── application.yml ├── 78.spring-cloud-alibaba-sentinelresource/ │ ├── consumer/ │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ ├── java/ │ │ │ └── cc/ │ │ │ └── mrbird/ │ │ │ └── consumer/ │ │ │ └── ConsumerApplication.java │ │ └── resources/ │ │ └── application.yml │ ├── pom.xml │ └── provider/ │ ├── pom.xml │ └── src/ │ └── main/ │ ├── java/ │ │ └── cc/ │ │ └── mrbird/ │ │ └── provider/ │ │ └── ProviderApplication.java │ └── resources/ │ └── application.yml ├── LICENSE └── readme.md ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ */.settings/ */target/ */.classpath */.project ================================================ FILE: 01.Start-Spring-Boot/pom.xml ================================================ 4.0.0 com.springboot Start-Spring-Boot 0.0.1-SNAPSHOT jar Start-Spring-Boot Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.9.RELEASE UTF-8 UTF-8 1.7 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test test nexus-aliyun Nexus aliyun http://maven.aliyun.com/nexus/content/groups/public org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 01.Start-Spring-Boot/src/main/java/com/springboot/demo/DemoApplication.java ================================================ package com.springboot.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @SpringBootApplication public class DemoApplication { @RequestMapping("/") String index() { return "hello spring boot"; } public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ================================================ FILE: 01.Start-Spring-Boot/src/main/resources/application.properties ================================================ ================================================ FILE: 01.Start-Spring-Boot/src/test/java/com/springboot/demo/DemoApplicationTests.java ================================================ package com.springboot.demo; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) @SpringBootTest public class DemoApplicationTests { @Test public void contextLoads() { } } ================================================ FILE: 02.Spring-Boot-Config/pom.xml ================================================ 4.0.0 com.springboot Spring-Boot-Config 0.0.1-SNAPSHOT jar Spring-Boot-Config Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.9.RELEASE UTF-8 UTF-8 1.7 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test test nexus-aliyun Nexus aliyun http://maven.aliyun.com/nexus/content/groups/public org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 02.Spring-Boot-Config/src/main/java/com/springboot/Application.java ================================================ package com.springboot; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.context.properties.EnableConfigurationProperties; import com.springboot.bean.ConfigBean; import com.springboot.bean.TestConfigBean; @SpringBootApplication @EnableConfigurationProperties({ConfigBean.class,TestConfigBean.class}) //@ImportResource({"classpath:some-application.xml"}) public class Application { public static void main(String[] args) { SpringApplication app = new SpringApplication(Application.class); app.setAddCommandLineProperties(false); app.run(args); } } ================================================ FILE: 02.Spring-Boot-Config/src/main/java/com/springboot/bean/BlogProperties.java ================================================ package com.springboot.bean; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @Component public class BlogProperties { @Value("${mrbird.blog.name}") private String name; @Value("${mrbird.blog.title}") private String title; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } } ================================================ FILE: 02.Spring-Boot-Config/src/main/java/com/springboot/bean/ConfigBean.java ================================================ package com.springboot.bean; import org.springframework.boot.context.properties.ConfigurationProperties; @ConfigurationProperties(prefix="mrbird.blog") public class ConfigBean { private String name; private String title; private String wholeTitle; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getWholeTitle() { return wholeTitle; } public void setWholeTitle(String wholeTitle) { this.wholeTitle = wholeTitle; } } ================================================ FILE: 02.Spring-Boot-Config/src/main/java/com/springboot/bean/TestConfigBean.java ================================================ package com.springboot.bean; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import org.springframework.stereotype.Component; @Configuration @ConfigurationProperties(prefix="test") @PropertySource("classpath:test.properties") @Component public class TestConfigBean { private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } ================================================ FILE: 02.Spring-Boot-Config/src/main/java/com/springboot/controller/IndexController.java ================================================ package com.springboot.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.springboot.bean.BlogProperties; import com.springboot.bean.ConfigBean; import com.springboot.bean.TestConfigBean; @RestController public class IndexController { @Autowired private BlogProperties blogProperties; @Autowired private ConfigBean configBean; @Autowired private TestConfigBean testConfigBean; @RequestMapping("/") String index() { return testConfigBean.getName()+","+testConfigBean.getAge(); } } ================================================ FILE: 02.Spring-Boot-Config/src/main/resources/application-dev.properties ================================================ server.port=8080 ================================================ FILE: 02.Spring-Boot-Config/src/main/resources/application-prod.properties ================================================ server.port=8081 ================================================ FILE: 02.Spring-Boot-Config/src/main/resources/application.properties ================================================ mrbird.blog.name=mrbird's blog mrbird.blog.title=Spring Boot mrbird.blog.wholeTitle=${mrbird.blog.name}--${mrbird.blog.title} spring.profiles.active=dev ================================================ FILE: 02.Spring-Boot-Config/src/main/resources/banner.txt ================================================ _ _ _ _ _ _ / \ / \ / \ / \ / \ / \ ( m | r | b | i | r | d ) \_/ \_/ \_/ \_/ \_/ \_/ ================================================ FILE: 02.Spring-Boot-Config/src/main/resources/test.properties ================================================ test.name=KangKang test.age=25 ================================================ FILE: 02.Spring-Boot-Config/src/test/java/com/springboot/demo/DemoApplicationTests.java ================================================ package com.springboot.demo; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) @SpringBootTest public class DemoApplicationTests { @Test public void contextLoads() { } } ================================================ FILE: 03.Spring-Boot-MyBatis/pom.xml ================================================ 4.0.0 com.springboot Spring-Boot-MyBatis 0.0.1-SNAPSHOT jar demo Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.9.RELEASE UTF-8 UTF-8 1.7 org.springframework.boot spring-boot-starter-web org.mybatis.spring.boot mybatis-spring-boot-starter 1.3.1 org.springframework.boot spring-boot-starter-test test com.oracle ojdbc6 6.0 com.alibaba druid-spring-boot-starter 1.1.6 org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 03.Spring-Boot-MyBatis/src/main/java/com/springboot/Application.java ================================================ package com.springboot; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class,args); } } ================================================ FILE: 03.Spring-Boot-MyBatis/src/main/java/com/springboot/bean/Student.java ================================================ package com.springboot.bean; import java.io.Serializable; public class Student implements Serializable{ private static final long serialVersionUID = -339516038496531943L; private String sno; private String name; private String sex; public String getSno() { return sno; } public void setSno(String sno) { this.sno = sno; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } } ================================================ FILE: 03.Spring-Boot-MyBatis/src/main/java/com/springboot/controller/TestController.java ================================================ package com.springboot.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import com.springboot.bean.Student; import com.springboot.service.StudentService; @RestController public class TestController { @Autowired private StudentService studentService; @RequestMapping( value = "/querystudent", method = RequestMethod.GET) public Student queryStudentBySno(String sno) { return this.studentService.queryStudentBySno(sno); } } ================================================ FILE: 03.Spring-Boot-MyBatis/src/main/java/com/springboot/mapper/StudentMapper.java ================================================ package com.springboot.mapper; import org.apache.ibatis.annotations.Delete; import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Results; import org.apache.ibatis.annotations.Result; import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.Update; import org.springframework.stereotype.Component; import com.springboot.bean.Student; @Component @Mapper public interface StudentMapper { @Insert("insert into student(sno,sname,ssex) values(#{sno},#{name},#{sex})") int add(Student student); @Update("update student set sname=#{name},ssex=#{sex} where sno=#{sno}") int update(Student student); @Delete("delete from student where sno=#{sno}") int deleteBysno(String sno); @Select("select * from student where sno=#{sno}") @Results(id = "student",value= { @Result(property = "sno", column = "sno", javaType = String.class), @Result(property = "name", column = "sname", javaType = String.class), @Result(property = "sex", column = "ssex", javaType = String.class) }) Student queryStudentBySno(String sno); } ================================================ FILE: 03.Spring-Boot-MyBatis/src/main/java/com/springboot/service/StudentService.java ================================================ package com.springboot.service; import com.springboot.bean.Student; public interface StudentService { int add(Student student); int update(Student student); int deleteBysno(String sno); Student queryStudentBySno(String sno); } ================================================ FILE: 03.Spring-Boot-MyBatis/src/main/java/com/springboot/service/impl/StudentServiceImp.java ================================================ package com.springboot.service.impl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.springboot.bean.Student; import com.springboot.mapper.StudentMapper; import com.springboot.service.StudentService; @Service("studentService") public class StudentServiceImp implements StudentService{ @Autowired private StudentMapper studentMapper; @Override public int add(Student student) { return this.studentMapper.add(student); } @Override public int update(Student student) { return this.studentMapper.update(student); } @Override public int deleteBysno(String sno) { return this.studentMapper.deleteBysno(sno); } @Override public Student queryStudentBySno(String sno) { return this.studentMapper.queryStudentBySno(sno); } } ================================================ FILE: 03.Spring-Boot-MyBatis/src/main/resources/application.yml ================================================ server: context-path: /web spring: datasource: druid: # 数据库访问配置, 使用druid数据源 type: com.alibaba.druid.pool.DruidDataSource driver-class-name: oracle.jdbc.driver.OracleDriver url: jdbc:oracle:thin:@localhost:1521:ORCL username: test password: 123456 # 连接池配置 initial-size: 5 min-idle: 5 max-active: 20 # 连接等待超时时间 max-wait: 30000 # 配置检测可以关闭的空闲连接间隔时间 time-between-eviction-runs-millis: 60000 # 配置连接在池中的最小生存时间 min-evictable-idle-time-millis: 300000 validation-query: select '1' from dual test-while-idle: true test-on-borrow: false test-on-return: false # 打开PSCache,并且指定每个连接上PSCache的大小 pool-prepared-statements: true max-open-prepared-statements: 20 max-pool-prepared-statement-per-connection-size: 20 # 配置监控统计拦截的filters, 去掉后监控界面sql无法统计, 'wall'用于防火墙 filters: stat,wall # Spring监控AOP切入点,如x.y.z.service.*,配置多个英文逗号分隔 aop-patterns: com.springboot.servie.* # WebStatFilter配置 web-stat-filter: enabled: true # 添加过滤规则 url-pattern: /* # 忽略过滤的格式 exclusions: '*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*' # StatViewServlet配置 stat-view-servlet: enabled: true # 访问路径为/druid时,跳转到StatViewServlet url-pattern: /druid/* # 是否能够重置数据 reset-enable: false # 需要账号密码才能访问控制台 login-username: druid login-password: druid123 # IP白名单 # allow: 127.0.0.1 # IP黑名单(共同存在时,deny优先于allow) # deny: 192.168.1.218 # 配置StatFilter filter: stat: log-slow-sql: true ================================================ FILE: 03.Spring-Boot-MyBatis/src/main/resources/init.sql ================================================ CREATE TABLE STUDENT ( SNO VARCHAR2(3 BYTE) NOT NULL , SNAME VARCHAR2(9 BYTE) NOT NULL , SSEX CHAR(2 BYTE) NOT NULL ); INSERT INTO STUDENT VALUES ('001', 'KangKang', 'M '); INSERT INTO STUDENT VALUES ('002', 'Mike', 'M '); INSERT INTO STUDENT VALUES ('003', 'Jane', 'F '); ================================================ FILE: 04.Spring-Boot-JdbcTemplate/pom.xml ================================================ 4.0.0 com.springboot Spring-Boot-JdbcTemplate 0.0.1-SNAPSHOT jar demo Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.9.RELEASE UTF-8 UTF-8 1.7 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-jdbc org.springframework.boot spring-boot-starter-test test com.oracle ojdbc6 6.0 com.alibaba druid-spring-boot-starter 1.1.6 nexus-aliyun Nexus aliyun http://maven.aliyun.com/nexus/content/groups/public org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 04.Spring-Boot-JdbcTemplate/src/main/java/com/springboot/Application.java ================================================ package com.springboot; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class,args); } } ================================================ FILE: 04.Spring-Boot-JdbcTemplate/src/main/java/com/springboot/bean/Student.java ================================================ package com.springboot.bean; import java.io.Serializable; public class Student implements Serializable{ private static final long serialVersionUID = -339516038496531943L; private String sno; private String name; private String sex; public String getSno() { return sno; } public void setSno(String sno) { this.sno = sno; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } } ================================================ FILE: 04.Spring-Boot-JdbcTemplate/src/main/java/com/springboot/controller/TestController.java ================================================ package com.springboot.controller; import java.util.List; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import com.springboot.bean.Student; import com.springboot.service.StudentService; @RestController public class TestController { @Autowired private StudentService studentService; @RequestMapping(value = "/querystudent", method = RequestMethod.GET) public Student queryStudentBySno(String sno) { return this.studentService.queryStudentBySno(sno); } @RequestMapping(value = "/queryallstudent") public List> queryAllStudent() { return this.studentService.queryStudentListMap(); } @RequestMapping(value = "/addstudent", method = RequestMethod.GET) public int saveStudent(String sno,String name,String sex) { Student student = new Student(); student.setSno(sno); student.setName(name); student.setSex(sex); return this.studentService.add(student); } @RequestMapping(value = "deletestudent", method = RequestMethod.GET) public int deleteStudentBySno(String sno) { return this.studentService.deleteBysno(sno); } } ================================================ FILE: 04.Spring-Boot-JdbcTemplate/src/main/java/com/springboot/dao/StudentDao.java ================================================ package com.springboot.dao; import java.util.List; import java.util.Map; import com.springboot.bean.Student; public interface StudentDao { int add(Student student); int update(Student student); int deleteBysno(String sno); List> queryStudentsListMap(); Student queryStudentBySno(String sno); } ================================================ FILE: 04.Spring-Boot-JdbcTemplate/src/main/java/com/springboot/dao/impl/StudentDaoImp.java ================================================ package com.springboot.dao.impl; import java.sql.Types; import java.util.List; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.stereotype.Repository; import com.springboot.bean.Student; import com.springboot.dao.StudentDao; import com.springboot.mapper.StudentMapper; @Repository("studentDao") public class StudentDaoImp implements StudentDao { @Autowired private JdbcTemplate jdbcTemplate; @Override public int add(Student student) { // String sql = "insert into student(sno,sname,ssex) values(?,?,?)"; // Object[] args = { student.getSno(), student.getName(), student.getSex() }; // int[] argTypes = { Types.VARCHAR, Types.VARCHAR, Types.VARCHAR }; // return this.jdbcTemplate.update(sql, args, argTypes); String sql = "insert into student(sno,sname,ssex) values(:sno,:name,:sex)"; NamedParameterJdbcTemplate npjt = new NamedParameterJdbcTemplate(this.jdbcTemplate.getDataSource()); return npjt.update(sql, new BeanPropertySqlParameterSource(student)); } @Override public int update(Student student) { String sql = "update student set sname = ?,ssex = ? where sno = ?"; Object[] args = { student.getName(), student.getSex(), student.getSno() }; int[] argTypes = { Types.VARCHAR, Types.VARCHAR, Types.VARCHAR }; return this.jdbcTemplate.update(sql, args, argTypes); } @Override public int deleteBysno(String sno) { String sql = "delete from student where sno = ?"; Object[] args = { sno }; int[] argTypes = { Types.VARCHAR }; return this.jdbcTemplate.update(sql, args, argTypes); } @Override public List> queryStudentsListMap() { String sql = "select * from student"; return this.jdbcTemplate.queryForList(sql); } @Override public Student queryStudentBySno(String sno) { String sql = "select * from student where sno = ?"; Object[] args = { sno }; int[] argTypes = { Types.VARCHAR }; List studentList = this.jdbcTemplate.query(sql, args, argTypes, new StudentMapper()); if (studentList != null && studentList.size() > 0) { return studentList.get(0); } else { return null; } } } ================================================ FILE: 04.Spring-Boot-JdbcTemplate/src/main/java/com/springboot/mapper/StudentMapper.java ================================================ package com.springboot.mapper; import java.sql.ResultSet; import java.sql.SQLException; import org.springframework.jdbc.core.RowMapper; import com.springboot.bean.Student; public class StudentMapper implements RowMapper{ @Override public Student mapRow(ResultSet rs, int rowNum) throws SQLException { Student student = new Student(); student.setSno(rs.getString("sno")); student.setName(rs.getString("sname")); student.setSex(rs.getString("ssex")); return student; } } ================================================ FILE: 04.Spring-Boot-JdbcTemplate/src/main/java/com/springboot/service/StudentService.java ================================================ package com.springboot.service; import java.util.List; import java.util.Map; import com.springboot.bean.Student; public interface StudentService { int add(Student student); int update(Student student); int deleteBysno(String sno); List> queryStudentListMap(); Student queryStudentBySno(String sno); } ================================================ FILE: 04.Spring-Boot-JdbcTemplate/src/main/java/com/springboot/service/impl/StudentServiceImp.java ================================================ package com.springboot.service.impl; import java.util.List; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.springboot.bean.Student; import com.springboot.dao.StudentDao; import com.springboot.mapper.StudentMapper; import com.springboot.service.StudentService; @Service("studentService") public class StudentServiceImp implements StudentService { @Autowired private StudentDao studentDao; @Override public int add(Student student) { return this.studentDao.add(student); } @Override public int update(Student student) { return this.studentDao.update(student); } @Override public int deleteBysno(String sno) { return this.studentDao.deleteBysno(sno); } @Override public List> queryStudentListMap() { return this.studentDao.queryStudentsListMap(); } @Override public Student queryStudentBySno(String sno) { return this.studentDao.queryStudentBySno(sno); } } ================================================ FILE: 04.Spring-Boot-JdbcTemplate/src/main/resources/application.yml ================================================ server: context-path: /web spring: datasource: druid: # 数据库访问配置, 使用druid数据源 type: com.alibaba.druid.pool.DruidDataSource driver-class-name: oracle.jdbc.driver.OracleDriver url: jdbc:oracle:thin:@localhost:1521:ORCL username: test password: 123456 # 连接池配置 initial-size: 5 min-idle: 5 max-active: 20 # 连接等待超时时间 max-wait: 30000 # 配置检测可以关闭的空闲连接间隔时间 time-between-eviction-runs-millis: 60000 # 配置连接在池中的最小生存时间 min-evictable-idle-time-millis: 300000 validation-query: select '1' from dual test-while-idle: true test-on-borrow: false test-on-return: false # 打开PSCache,并且指定每个连接上PSCache的大小 pool-prepared-statements: true max-open-prepared-statements: 20 max-pool-prepared-statement-per-connection-size: 20 # 配置监控统计拦截的filters, 去掉后监控界面sql无法统计, 'wall'用于防火墙 filters: stat,wall # Spring监控AOP切入点,如x.y.z.service.*,配置多个英文逗号分隔 aop-patterns: com.springboot.servie.* # WebStatFilter配置 web-stat-filter: enabled: true # 添加过滤规则 url-pattern: /* # 忽略过滤的格式 exclusions: '*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*' # StatViewServlet配置 stat-view-servlet: enabled: true # 访问路径为/druid时,跳转到StatViewServlet url-pattern: /druid/* # 是否能够重置数据 reset-enable: false # 需要账号密码才能访问控制台 login-username: druid login-password: druid123 # IP白名单 # allow: 127.0.0.1 # IP黑名单(共同存在时,deny优先于allow) # deny: 192.168.1.218 # 配置StatFilter filter: stat: log-slow-sql: true ================================================ FILE: 04.Spring-Boot-JdbcTemplate/src/main/resources/init.sql ================================================ CREATE TABLE STUDENT ( SNO VARCHAR2(3 BYTE) NOT NULL , SNAME VARCHAR2(9 BYTE) NOT NULL , SSEX CHAR(2 BYTE) NOT NULL ); INSERT INTO STUDENT VALUES ('001', 'KangKang', 'M '); INSERT INTO STUDENT VALUES ('002', 'Mike', 'M '); INSERT INTO STUDENT VALUES ('003', 'Jane', 'F '); ================================================ FILE: 05.Spring-Boot-MyBatis-MultiDataSource/pom.xml ================================================ 4.0.0 com.springboot Spring-Boot-MyBatis-MultiDataSource 1.0-snapshot jar demo Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.9.RELEASE UTF-8 UTF-8 1.7 org.springframework.boot spring-boot-starter-web org.mybatis.spring.boot mybatis-spring-boot-starter 1.3.1 org.springframework.boot spring-boot-starter-test test com.oracle ojdbc6 6.0 mysql mysql-connector-java com.alibaba druid-spring-boot-starter 1.1.6 org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 05.Spring-Boot-MyBatis-MultiDataSource/src/main/java/com/springboot/Application.java ================================================ package com.springboot; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class,args); } } ================================================ FILE: 05.Spring-Boot-MyBatis-MultiDataSource/src/main/java/com/springboot/controller/StudentController.java ================================================ package com.springboot.controller; import java.util.List; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.springboot.service.StudentService; @RestController public class StudentController { @Autowired private StudentService studentService; @RequestMapping("querystudentsfromoracle") public List> queryStudentsFromOracle(){ return this.studentService.getAllStudentsFromOralce(); } @RequestMapping("querystudentsfrommysql") public List> queryStudentsFromMysql(){ return this.studentService.getAllStudentsFromMysql(); } } ================================================ FILE: 05.Spring-Boot-MyBatis-MultiDataSource/src/main/java/com/springboot/datasource/MysqlDatasourceConfig.java ================================================ package com.springboot.datasource; import javax.sql.DataSource; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.annotation.MapperScan; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder; @Configuration @MapperScan(basePackages = MysqlDatasourceConfig.PACKAGE, sqlSessionFactoryRef = "mysqlSqlSessionFactory") public class MysqlDatasourceConfig { // mysqldao扫描路径 static final String PACKAGE = "com.springboot.mysqldao"; // mybatis mapper扫描路径 static final String MAPPER_LOCATION = "classpath:mapper/mysql/*.xml"; @Primary @Bean(name = "mysqldatasource") @ConfigurationProperties("spring.datasource.druid.mysql") public DataSource mysqlDataSource() { return DruidDataSourceBuilder.create().build(); } @Bean(name = "mysqlTransactionManager") @Primary public DataSourceTransactionManager mysqlTransactionManager() { return new DataSourceTransactionManager(mysqlDataSource()); } @Bean(name = "mysqlSqlSessionFactory") @Primary public SqlSessionFactory mysqlSqlSessionFactory(@Qualifier("mysqldatasource") DataSource dataSource) throws Exception { final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean(); sessionFactory.setDataSource(dataSource); //如果不使用xml的方式配置mapper,则可以省去下面这行mapper location的配置。 sessionFactory.setMapperLocations( new PathMatchingResourcePatternResolver().getResources(MysqlDatasourceConfig.MAPPER_LOCATION)); return sessionFactory.getObject(); } } ================================================ FILE: 05.Spring-Boot-MyBatis-MultiDataSource/src/main/java/com/springboot/datasource/OracleDatasourceConfig.java ================================================ package com.springboot.datasource; import javax.sql.DataSource; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.annotation.MapperScan; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder; @Configuration @MapperScan(basePackages = OracleDatasourceConfig.PACKAGE, sqlSessionFactoryRef = "oracleSqlSessionFactory") public class OracleDatasourceConfig { // oracledao扫描路径 static final String PACKAGE = "com.springboot.oracledao"; // mybatis mapper扫描路径 static final String MAPPER_LOCATION = "classpath:mapper/oracle/*.xml"; @Bean(name = "oracledatasource") @ConfigurationProperties("spring.datasource.druid.oracle") public DataSource oracleDataSource() { return DruidDataSourceBuilder.create().build(); } @Bean(name = "oracleTransactionManager") public DataSourceTransactionManager oracleTransactionManager() { return new DataSourceTransactionManager(oracleDataSource()); } @Bean(name = "oracleSqlSessionFactory") public SqlSessionFactory oracleSqlSessionFactory(@Qualifier("oracledatasource") DataSource dataSource) throws Exception { final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean(); sessionFactory.setDataSource(dataSource); //如果不使用xml的方式配置mapper,则可以省去下面这行mapper location的配置。 sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver() .getResources(OracleDatasourceConfig.MAPPER_LOCATION)); return sessionFactory.getObject(); } } ================================================ FILE: 05.Spring-Boot-MyBatis-MultiDataSource/src/main/java/com/springboot/mysqldao/MysqlStudentMapper.java ================================================ package com.springboot.mysqldao; import java.util.List; import java.util.Map; import org.apache.ibatis.annotations.Mapper; @Mapper public interface MysqlStudentMapper { List> getAllStudents(); } ================================================ FILE: 05.Spring-Boot-MyBatis-MultiDataSource/src/main/java/com/springboot/oracledao/OracleStudentMapper.java ================================================ package com.springboot.oracledao; import java.util.List; import java.util.Map; import org.apache.ibatis.annotations.Mapper; @Mapper public interface OracleStudentMapper { List> getAllStudents(); } ================================================ FILE: 05.Spring-Boot-MyBatis-MultiDataSource/src/main/java/com/springboot/service/StudentService.java ================================================ package com.springboot.service; import java.util.List; import java.util.Map; public interface StudentService { List> getAllStudentsFromOralce(); List> getAllStudentsFromMysql(); } ================================================ FILE: 05.Spring-Boot-MyBatis-MultiDataSource/src/main/java/com/springboot/service/impl/StudentServiceImp.java ================================================ package com.springboot.service.impl; import java.util.List; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.springboot.mysqldao.MysqlStudentMapper; import com.springboot.oracledao.OracleStudentMapper; import com.springboot.service.StudentService; @Service("studentService") public class StudentServiceImp implements StudentService{ @Autowired private OracleStudentMapper oracleStudentMapper; @Autowired private MysqlStudentMapper mysqlStudentMapper; @Override public List> getAllStudentsFromOralce() { return this.oracleStudentMapper.getAllStudents(); } @Override public List> getAllStudentsFromMysql() { return this.mysqlStudentMapper.getAllStudents(); } } ================================================ FILE: 05.Spring-Boot-MyBatis-MultiDataSource/src/main/resources/application.yml ================================================ server: context-path: /web spring: datasource: druid: # 数据库访问配置, 使用druid数据源 # 数据源1 mysql mysql: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&rewriteBatchedStatements=true&autoReconnect=true&failOverReadOnly=false&zeroDateTimeBehavior=convertToNull username: root password: 123456 # 数据源2 oracle oracle: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: oracle.jdbc.driver.OracleDriver url: jdbc:oracle:thin:@localhost:1521:ORCL username: test password: 123456 # 连接池配置 initial-size: 5 min-idle: 5 max-active: 20 # 连接等待超时时间 max-wait: 30000 # 配置检测可以关闭的空闲连接间隔时间 time-between-eviction-runs-millis: 60000 # 配置连接在池中的最小生存时间 min-evictable-idle-time-millis: 300000 validation-query: select '1' from dual test-while-idle: true test-on-borrow: false test-on-return: false # 打开PSCache,并且指定每个连接上PSCache的大小 pool-prepared-statements: true max-open-prepared-statements: 20 max-pool-prepared-statement-per-connection-size: 20 # 配置监控统计拦截的filters, 去掉后监控界面sql无法统计, 'wall'用于防火墙 filters: stat,wall # Spring监控AOP切入点,如x.y.z.service.*,配置多个英文逗号分隔 aop-patterns: com.springboot.servie.* # WebStatFilter配置 web-stat-filter: enabled: true # 添加过滤规则 url-pattern: /* # 忽略过滤的格式 exclusions: '*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*' # StatViewServlet配置 stat-view-servlet: enabled: true # 访问路径为/druid时,跳转到StatViewServlet url-pattern: /druid/* # 是否能够重置数据 reset-enable: false # 需要账号密码才能访问控制台 login-username: druid login-password: druid123 # IP白名单 # allow: 127.0.0.1 # IP黑名单(共同存在时,deny优先于allow) # deny: 192.168.1.218 # 配置StatFilter filter: stat: log-slow-sql: true ================================================ FILE: 05.Spring-Boot-MyBatis-MultiDataSource/src/main/resources/mapper/mysql/MysqlStudentMapper.xml ================================================ ================================================ FILE: 05.Spring-Boot-MyBatis-MultiDataSource/src/main/resources/mapper/oracle/OracleStudentMapper.xml ================================================ ================================================ FILE: 05.Spring-Boot-MyBatis-MultiDataSource/src/main/resources/mysql_sql.sql ================================================ /* Navicat MySQL Data Transfer Source Server : localhost_3306 Source Server Version : 50717 Source Host : localhost:3306 Source Database : test Target Server Type : MYSQL Target Server Version : 50717 File Encoding : 65001 Date: 2018-05-02 14:32:22 */ SET FOREIGN_KEY_CHECKS=0; -- ---------------------------- -- Table structure for student -- ---------------------------- DROP TABLE IF EXISTS `student`; CREATE TABLE `student` ( `SNO` varchar(3) NOT NULL, `SNAME` varchar(10) NOT NULL, `SSEX` char(2) NOT NULL, `DATASOURCE` varchar(10) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of student -- ---------------------------- INSERT INTO `student` VALUES ('001', 'KangKang', 'M', 'mysql'); INSERT INTO `student` VALUES ('002', 'Mike', 'M', 'mysql'); ================================================ FILE: 05.Spring-Boot-MyBatis-MultiDataSource/src/main/resources/oracle_sql.sql ================================================ /* Navicat Oracle Data Transfer Oracle Client Version : 11.2.0.1.0 Source Server : localhost_test Source Server Version : 110200 Source Host : localhost:1521 Source Schema : TEST Target Server Type : ORACLE Target Server Version : 110200 File Encoding : 65001 Date: 2018-05-02 14:31:18 */ -- ---------------------------- -- Table structure for STUDENT -- ---------------------------- DROP TABLE STUDENT; CREATE TABLE STUDENT ( SNO VARCHAR2(3 BYTE) NOT NULL , SNAME VARCHAR2(9 BYTE) NOT NULL , SSEX CHAR(2 BYTE) NOT NULL , DATASOURCE VARCHAR2(10 BYTE) NULL ) LOGGING NOCOMPRESS NOCACHE ; -- ---------------------------- -- Records of STUDENT -- ---------------------------- INSERT INTO STUDENT VALUES ('001', 'KangKang', 'M ', 'oracle'); INSERT INTO STUDENT VALUES ('002', 'Mike', 'M ', 'oracle'); INSERT INTO STUDENT VALUES ('003', 'Jane', 'F ', 'oracle'); INSERT INTO STUDENT VALUES ('004', 'Maria', 'F ', 'oracle'); -- ---------------------------- -- Checks structure for table STUDENT -- ---------------------------- ALTER TABLE STUDENT ADD CHECK (SNO IS NOT NULL); ALTER TABLE STUDENT ADD CHECK (SNAME IS NOT NULL); ALTER TABLE STUDENT ADD CHECK (SSEX IS NOT NULL); ================================================ FILE: 06.Spring-Boot-JdbcTemplate-MultiDataSource/pom.xml ================================================ 4.0.0 com.springboot Spring-Boot-JdbcTemplate-MultiDataSource 1.0-snapshot jar demo Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.9.RELEASE UTF-8 UTF-8 1.7 org.springframework.boot spring-boot-starter-web org.mybatis.spring.boot mybatis-spring-boot-starter 1.3.1 org.springframework.boot spring-boot-starter-test test com.oracle ojdbc6 6.0 mysql mysql-connector-java com.alibaba druid-spring-boot-starter 1.1.6 org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 06.Spring-Boot-JdbcTemplate-MultiDataSource/src/main/java/com/springboot/Application.java ================================================ package com.springboot; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class,args); } } ================================================ FILE: 06.Spring-Boot-JdbcTemplate-MultiDataSource/src/main/java/com/springboot/controller/StudentController.java ================================================ package com.springboot.controller; import java.util.List; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.springboot.service.StudentService; @RestController public class StudentController { @Autowired private StudentService studentService; @RequestMapping("querystudentsfromoracle") public List> queryStudentsFromOracle(){ return this.studentService.getAllStudentsFromOralce(); } @RequestMapping("querystudentsfrommysql") public List> queryStudentsFromMysql(){ return this.studentService.getAllStudentsFromMysql(); } } ================================================ FILE: 06.Spring-Boot-JdbcTemplate-MultiDataSource/src/main/java/com/springboot/dao/MysqlStudentDao.java ================================================ package com.springboot.dao; import java.util.List; import java.util.Map; public interface MysqlStudentDao { List> getAllStudents(); } ================================================ FILE: 06.Spring-Boot-JdbcTemplate-MultiDataSource/src/main/java/com/springboot/dao/OracleStudentDao.java ================================================ package com.springboot.dao; import java.util.List; import java.util.Map; public interface OracleStudentDao { List> getAllStudents(); } ================================================ FILE: 06.Spring-Boot-JdbcTemplate-MultiDataSource/src/main/java/com/springboot/dao/impl/MysqlStudentDaoImp.java ================================================ package com.springboot.dao.impl; import java.util.List; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; import com.springboot.dao.MysqlStudentDao; @Repository public class MysqlStudentDaoImp implements MysqlStudentDao{ @Autowired @Qualifier("mysqlJdbcTemplate") private JdbcTemplate jdbcTemplate; @Override public List> getAllStudents() { return this.jdbcTemplate.queryForList("select * from student"); } } ================================================ FILE: 06.Spring-Boot-JdbcTemplate-MultiDataSource/src/main/java/com/springboot/dao/impl/OracleStudentDaoImp.java ================================================ package com.springboot.dao.impl; import java.util.List; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; import com.springboot.dao.OracleStudentDao; @Repository public class OracleStudentDaoImp implements OracleStudentDao{ @Autowired @Qualifier("oracleJdbcTemplate") private JdbcTemplate jdbcTemplate; @Override public List> getAllStudents() { return this.jdbcTemplate.queryForList("select * from student"); } } ================================================ FILE: 06.Spring-Boot-JdbcTemplate-MultiDataSource/src/main/java/com/springboot/datasource/DataSourceConfig.java ================================================ package com.springboot.datasource; import javax.sql.DataSource; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.jdbc.core.JdbcTemplate; import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder; @Configuration public class DataSourceConfig { @Primary @Bean(name = "mysqldatasource") @ConfigurationProperties("spring.datasource.druid.mysql") public DataSource dataSourceOne(){ return DruidDataSourceBuilder.create().build(); } @Bean(name = "oracledatasource") @ConfigurationProperties("spring.datasource.druid.oracle") public DataSource dataSourceTwo(){ return DruidDataSourceBuilder.create().build(); } @Bean(name = "mysqlJdbcTemplate") public JdbcTemplate primaryJdbcTemplate( @Qualifier("mysqldatasource") DataSource dataSource) { return new JdbcTemplate(dataSource); } @Bean(name = "oracleJdbcTemplate") public JdbcTemplate secondaryJdbcTemplate( @Qualifier("oracledatasource") DataSource dataSource) { return new JdbcTemplate(dataSource); } } ================================================ FILE: 06.Spring-Boot-JdbcTemplate-MultiDataSource/src/main/java/com/springboot/service/StudentService.java ================================================ package com.springboot.service; import java.util.List; import java.util.Map; public interface StudentService { List> getAllStudentsFromOralce(); List> getAllStudentsFromMysql(); } ================================================ FILE: 06.Spring-Boot-JdbcTemplate-MultiDataSource/src/main/java/com/springboot/service/impl/StudentServiceImp.java ================================================ package com.springboot.service.impl; import java.util.List; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.springboot.dao.MysqlStudentDao; import com.springboot.dao.OracleStudentDao; import com.springboot.service.StudentService; @Service("studentService") public class StudentServiceImp implements StudentService{ @Autowired private OracleStudentDao oracleStudentDao; @Autowired private MysqlStudentDao mysqlStudentDao; @Override public List> getAllStudentsFromOralce() { return this.oracleStudentDao.getAllStudents(); } @Override public List> getAllStudentsFromMysql() { return this.mysqlStudentDao.getAllStudents(); } } ================================================ FILE: 06.Spring-Boot-JdbcTemplate-MultiDataSource/src/main/resources/application.yml ================================================ server: context-path: /web spring: datasource: druid: # 数据库访问配置, 使用druid数据源 # 数据源1 mysql mysql: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&rewriteBatchedStatements=true&autoReconnect=true&failOverReadOnly=false&zeroDateTimeBehavior=convertToNull username: root password: 123456 # 数据源2 oracle oracle: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: oracle.jdbc.driver.OracleDriver url: jdbc:oracle:thin:@localhost:1521:ORCL username: test password: 123456 # 连接池配置 initial-size: 5 min-idle: 5 max-active: 20 # 连接等待超时时间 max-wait: 30000 # 配置检测可以关闭的空闲连接间隔时间 time-between-eviction-runs-millis: 60000 # 配置连接在池中的最小生存时间 min-evictable-idle-time-millis: 300000 validation-query: select '1' from dual test-while-idle: true test-on-borrow: false test-on-return: false # 打开PSCache,并且指定每个连接上PSCache的大小 pool-prepared-statements: true max-open-prepared-statements: 20 max-pool-prepared-statement-per-connection-size: 20 # 配置监控统计拦截的filters, 去掉后监控界面sql无法统计, 'wall'用于防火墙 filters: stat,wall # Spring监控AOP切入点,如x.y.z.service.*,配置多个英文逗号分隔 aop-patterns: com.springboot.servie.* # WebStatFilter配置 web-stat-filter: enabled: true # 添加过滤规则 url-pattern: /* # 忽略过滤的格式 exclusions: '*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*' # StatViewServlet配置 stat-view-servlet: enabled: true # 访问路径为/druid时,跳转到StatViewServlet url-pattern: /druid/* # 是否能够重置数据 reset-enable: false # 需要账号密码才能访问控制台 login-username: druid login-password: druid123 # IP白名单 # allow: 127.0.0.1 # IP黑名单(共同存在时,deny优先于allow) # deny: 192.168.1.218 # 配置StatFilter filter: stat: log-slow-sql: true ================================================ FILE: 06.Spring-Boot-JdbcTemplate-MultiDataSource/src/main/resources/mysql_sql.sql ================================================ /* Navicat MySQL Data Transfer Source Server : localhost_3306 Source Server Version : 50717 Source Host : localhost:3306 Source Database : test Target Server Type : MYSQL Target Server Version : 50717 File Encoding : 65001 Date: 2018-05-02 14:32:22 */ SET FOREIGN_KEY_CHECKS=0; -- ---------------------------- -- Table structure for student -- ---------------------------- DROP TABLE IF EXISTS `student`; CREATE TABLE `student` ( `SNO` varchar(3) NOT NULL, `SNAME` varchar(10) NOT NULL, `SSEX` char(2) NOT NULL, `DATASOURCE` varchar(10) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of student -- ---------------------------- INSERT INTO `student` VALUES ('001', 'KangKang', 'M', 'mysql'); INSERT INTO `student` VALUES ('002', 'Mike', 'M', 'mysql'); ================================================ FILE: 06.Spring-Boot-JdbcTemplate-MultiDataSource/src/main/resources/oracle_sql.sql ================================================ /* Navicat Oracle Data Transfer Oracle Client Version : 11.2.0.1.0 Source Server : localhost_test Source Server Version : 110200 Source Host : localhost:1521 Source Schema : TEST Target Server Type : ORACLE Target Server Version : 110200 File Encoding : 65001 Date: 2018-05-02 14:31:18 */ -- ---------------------------- -- Table structure for STUDENT -- ---------------------------- DROP TABLE STUDENT; CREATE TABLE STUDENT ( SNO VARCHAR2(3 BYTE) NOT NULL , SNAME VARCHAR2(9 BYTE) NOT NULL , SSEX CHAR(2 BYTE) NOT NULL , DATASOURCE VARCHAR2(10 BYTE) NULL ) LOGGING NOCOMPRESS NOCACHE ; -- ---------------------------- -- Records of STUDENT -- ---------------------------- INSERT INTO STUDENT VALUES ('001', 'KangKang', 'M ', 'oracle'); INSERT INTO STUDENT VALUES ('002', 'Mike', 'M ', 'oracle'); INSERT INTO STUDENT VALUES ('003', 'Jane', 'F ', 'oracle'); INSERT INTO STUDENT VALUES ('004', 'Maria', 'F ', 'oracle'); -- ---------------------------- -- Checks structure for table STUDENT -- ---------------------------- ALTER TABLE STUDENT ADD CHECK (SNO IS NOT NULL); ALTER TABLE STUDENT ADD CHECK (SNAME IS NOT NULL); ALTER TABLE STUDENT ADD CHECK (SSEX IS NOT NULL); ================================================ FILE: 07.Spring-Boot-AOP-Log/pom.xml ================================================ 4.0.0 com.springboot Spring-Boot-AOP-Log 0.0.1-SNAPSHOT jar demo Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.9.RELEASE UTF-8 UTF-8 1.7 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test test org.springframework.boot spring-boot-starter-jdbc org.springframework.boot spring-boot-starter-aop com.oracle ojdbc6 6.0 com.alibaba druid-spring-boot-starter 1.1.6 org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 07.Spring-Boot-AOP-Log/src/main/java/com/springboot/Application.java ================================================ package com.springboot; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class,args); } } ================================================ FILE: 07.Spring-Boot-AOP-Log/src/main/java/com/springboot/annotation/Log.java ================================================ package com.springboot.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Log { String value() default ""; } ================================================ FILE: 07.Spring-Boot-AOP-Log/src/main/java/com/springboot/aspect/LogAspect.java ================================================ package com.springboot.aspect; import java.lang.reflect.Method; import java.util.Date; import javax.servlet.http.HttpServletRequest; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.LocalVariableTableParameterNameDiscoverer; import org.springframework.stereotype.Component; import com.springboot.annotation.Log; import com.springboot.dao.SysLogDao; import com.springboot.domain.SysLog; import com.springboot.util.HttpContextUtils; import com.springboot.util.IPUtils; @Aspect @Component public class LogAspect { @Autowired private SysLogDao sysLogDao; @Pointcut("@annotation(com.springboot.annotation.Log)") public void pointcut() { } @Around("pointcut()") public void around(ProceedingJoinPoint point) { long beginTime = System.currentTimeMillis(); try { // 执行方法 point.proceed(); } catch (Throwable e) { e.printStackTrace(); } // 执行时长(毫秒) long time = System.currentTimeMillis() - beginTime; // 保存日志 saveLog(point, time); } private void saveLog(ProceedingJoinPoint joinPoint, long time) { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); SysLog sysLog = new SysLog(); Log logAnnotation = method.getAnnotation(Log.class); if (logAnnotation != null) { // 注解上的描述 sysLog.setOperation(logAnnotation.value()); } // 请求的方法名 String className = joinPoint.getTarget().getClass().getName(); String methodName = signature.getName(); sysLog.setMethod(className + "." + methodName + "()"); // 请求的方法参数值 Object[] args = joinPoint.getArgs(); // 请求的方法参数名称 LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer(); String[] paramNames = u.getParameterNames(method); if (args != null && paramNames != null) { String params = ""; for (int i = 0; i < args.length; i++) { params += " " + paramNames[i] + ": " + args[i]; } sysLog.setParams(params); } // 获取request HttpServletRequest request = HttpContextUtils.getHttpServletRequest(); // 设置IP地址 sysLog.setIp(IPUtils.getIpAddr(request)); // 模拟一个用户名 sysLog.setUsername("mrbird"); sysLog.setTime((int) time); Date date = new Date(); sysLog.setCreateTime(date); // 保存系统日志 sysLogDao.saveSysLog(sysLog); } } ================================================ FILE: 07.Spring-Boot-AOP-Log/src/main/java/com/springboot/controller/TestController.java ================================================ package com.springboot.controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import com.springboot.annotation.Log; @RestController public class TestController { @Log("执行方法一") @GetMapping("/one") public void methodOne(String name) { } @Log("执行方法二") @GetMapping("/two") public void methodTwo() throws InterruptedException { Thread.sleep(2000); } @Log("执行方法三") @GetMapping("/three") public void methodThree(String name, String age) { } } ================================================ FILE: 07.Spring-Boot-AOP-Log/src/main/java/com/springboot/dao/SysLogDao.java ================================================ package com.springboot.dao; import com.springboot.domain.SysLog; public interface SysLogDao { void saveSysLog(SysLog syslog); } ================================================ FILE: 07.Spring-Boot-AOP-Log/src/main/java/com/springboot/dao/impl/SysLogDaoImp.java ================================================ package com.springboot.dao.impl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.stereotype.Repository; import com.springboot.dao.SysLogDao; import com.springboot.domain.SysLog; @Repository public class SysLogDaoImp implements SysLogDao { @Autowired private JdbcTemplate jdbcTemplate; @Override public void saveSysLog(SysLog syslog) { StringBuffer sql = new StringBuffer("insert into sys_log "); sql.append("(id,username,operation,time,method,params,ip,create_time) "); sql.append("values(seq_sys_log.nextval,:username,:operation,:time,:method,"); sql.append(":params,:ip,:createTime)"); NamedParameterJdbcTemplate npjt = new NamedParameterJdbcTemplate(this.jdbcTemplate.getDataSource()); npjt.update(sql.toString(), new BeanPropertySqlParameterSource(syslog)); } } ================================================ FILE: 07.Spring-Boot-AOP-Log/src/main/java/com/springboot/domain/SysLog.java ================================================ package com.springboot.domain; import java.io.Serializable; import java.util.Date; public class SysLog implements Serializable{ private static final long serialVersionUID = -6309732882044872298L; private Integer id; private String username; private String operation; private Integer time; private String method; private String params; private String ip; private Date createTime; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getOperation() { return operation; } public void setOperation(String operation) { this.operation = operation; } public Integer getTime() { return time; } public void setTime(Integer time) { this.time = time; } public String getMethod() { return method; } public void setMethod(String method) { this.method = method; } public String getParams() { return params; } public void setParams(String params) { this.params = params; } public String getIp() { return ip; } public void setIp(String ip) { this.ip = ip; } public Date getCreateTime() { return createTime; } public void setCreateTime(Date createTime) { this.createTime = createTime; } } ================================================ FILE: 07.Spring-Boot-AOP-Log/src/main/java/com/springboot/util/HttpContextUtils.java ================================================ package com.springboot.util; import javax.servlet.http.HttpServletRequest; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; public class HttpContextUtils { public static HttpServletRequest getHttpServletRequest() { return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); } } ================================================ FILE: 07.Spring-Boot-AOP-Log/src/main/java/com/springboot/util/IPUtils.java ================================================ package com.springboot.util; import javax.servlet.http.HttpServletRequest; public class IPUtils { /** * 获取IP地址 * * 使用Nginx等反向代理软件, 则不能通过request.getRemoteAddr()获取IP地址 * 如果使用了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP地址,X-Forwarded-For中第一个非unknown的有效IP字符串,则为真实IP地址 */ public static String getIpAddr(HttpServletRequest request) { String ip = request.getHeader("x-forwarded-for"); if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("WL-Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getRemoteAddr(); } return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip; } } ================================================ FILE: 07.Spring-Boot-AOP-Log/src/main/resources/application.yml ================================================ server: context-path: /web spring: datasource: druid: # 数据库访问配置, 使用druid数据源 type: com.alibaba.druid.pool.DruidDataSource driver-class-name: oracle.jdbc.driver.OracleDriver url: jdbc:oracle:thin:@localhost:1521:ORCL username: test password: 123456 # 连接池配置 initial-size: 5 min-idle: 5 max-active: 20 # 连接等待超时时间 max-wait: 30000 # 配置检测可以关闭的空闲连接间隔时间 time-between-eviction-runs-millis: 60000 # 配置连接在池中的最小生存时间 min-evictable-idle-time-millis: 300000 validation-query: select '1' from dual test-while-idle: true test-on-borrow: false test-on-return: false # 打开PSCache,并且指定每个连接上PSCache的大小 pool-prepared-statements: true max-open-prepared-statements: 20 max-pool-prepared-statement-per-connection-size: 20 # 配置监控统计拦截的filters, 去掉后监控界面sql无法统计, 'wall'用于防火墙 filters: stat,wall # Spring监控AOP切入点,如x.y.z.service.*,配置多个英文逗号分隔 aop-patterns: com.springboot.servie.* # WebStatFilter配置 web-stat-filter: enabled: true # 添加过滤规则 url-pattern: /* # 忽略过滤的格式 exclusions: '*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*' # StatViewServlet配置 stat-view-servlet: enabled: true # 访问路径为/druid时,跳转到StatViewServlet url-pattern: /druid/* # 是否能够重置数据 reset-enable: false # 需要账号密码才能访问控制台 login-username: druid login-password: druid123 # IP白名单 # allow: 127.0.0.1 # IP黑名单(共同存在时,deny优先于allow) # deny: 192.168.1.218 # 配置StatFilter filter: stat: log-slow-sql: true ================================================ FILE: 07.Spring-Boot-AOP-Log/src/main/resources/init.sql ================================================ CREATE TABLE SYS_LOG ( ID NUMBER(20) NOT NULL , USERNAME VARCHAR2(50 BYTE) NULL , OPERATION VARCHAR2(50 BYTE) NULL , TIME NUMBER(11) NULL , METHOD VARCHAR2(200 BYTE) NULL , PARAMS VARCHAR2(500 BYTE) NULL , IP VARCHAR2(64 BYTE) NULL , CREATE_TIME DATE NULL ); COMMENT ON COLUMN SYS_LOG.USERNAME IS '用户名'; COMMENT ON COLUMN SYS_LOG.OPERATION IS '用户操作'; COMMENT ON COLUMN SYS_LOG.TIME IS '响应时间'; COMMENT ON COLUMN SYS_LOG.METHOD IS '请求方法'; COMMENT ON COLUMN SYS_LOG.PARAMS IS '请求参数'; COMMENT ON COLUMN SYS_LOG.IP IS 'IP地址'; COMMENT ON COLUMN SYS_LOG.CREATE_TIME IS '创建时间'; CREATE SEQUENCE seq_sys_log START WITH 1 INCREMENT BY 1; ================================================ FILE: 08.Spring-Boot-Thymeleaf/pom.xml ================================================ 4.0.0 com.springboot Spring-Boot-Thymeleaf 0.0.1-SNAPSHOT jar demo Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.9.RELEASE UTF-8 UTF-8 1.7 3.0.2.RELEASE 2.0.1 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-thymeleaf org.springframework.boot spring-boot-starter-test test org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 08.Spring-Boot-Thymeleaf/src/main/java/com/springboot/Application.java ================================================ package com.springboot; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class,args); } } ================================================ FILE: 08.Spring-Boot-Thymeleaf/src/main/java/com/springboot/bean/Account.java ================================================ package com.springboot.bean; public class Account { private String account; private String name; private String password; private String accountType; private String tel; public Account(String account, String name, String password, String accountType, String tel) { super(); this.account = account; this.name = name; this.password = password; this.accountType = accountType; this.tel = tel; } public String getAccount() { return account; } public void setAccount(String account) { this.account = account; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getAccountType() { return accountType; } public void setAccountType(String accountType) { this.accountType = accountType; } public String getTel() { return tel; } public void setTel(String tel) { this.tel = tel; } } ================================================ FILE: 08.Spring-Boot-Thymeleaf/src/main/java/com/springboot/controller/IndexController.java ================================================ package com.springboot.controller; import java.util.ArrayList; import java.util.List; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import com.springboot.bean.Account; @Controller public class IndexController { @RequestMapping("/account") public String index(Model m) { List list = new ArrayList(); list.add(new Account("KangKang", "康康", "e10adc3949ba59abbe56e", "超级管理员", "17777777777")); list.add(new Account("Mike", "麦克", "e10adc3949ba59abbe56e", "管理员", "13444444444")); list.add(new Account("Jane","简","e10adc3949ba59abbe56e","运维人员","18666666666")); list.add(new Account("Maria", "玛利亚", "e10adc3949ba59abbe56e", "清算人员", "19999999999")); m.addAttribute("accountList",list); return "account"; } } ================================================ FILE: 08.Spring-Boot-Thymeleaf/src/main/resources/application.properties ================================================ server.context-path=/web spring.thymeleaf.cache=false ================================================ FILE: 08.Spring-Boot-Thymeleaf/src/main/resources/static/css/style.css ================================================ table { margin: 20px 40px 20px 0px; width: 100%; border-collapse: collapse; border-spacing: 0; table-layout: automatic; word-wrap: break-all } table>tbody>tr:nth-of-type(odd) { background-color: #F7F7F7 } th, td { padding: 8px; text-align: left; vertical-align: middle; font-weight: normal; font-size: 12px; border-bottom: 1px solid #fff; } th { padding-bottom: 10px; color: #fff; font-weight: 700; background: rgba(66, 185, 131, .9) } td { border-bottom-width: 1px } ================================================ FILE: 08.Spring-Boot-Thymeleaf/src/main/resources/templates/account.html ================================================ account
no account name password accountType tel
================================================ FILE: 09.Spring-Boot-Redis-Cache/pom.xml ================================================ 4.0.0 com.springboot Spring-Boot-Redis-Cache 0.0.1-SNAPSHOT jar demo Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.9.RELEASE UTF-8 UTF-8 1.7 org.springframework.boot spring-boot-starter-web org.mybatis.spring.boot mybatis-spring-boot-starter 1.3.1 org.springframework.boot spring-boot-starter-test test org.springframework.boot spring-boot-starter-cache org.springframework.boot spring-boot-starter-data-redis com.oracle ojdbc6 6.0 com.alibaba druid-spring-boot-starter 1.1.6 org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 09.Spring-Boot-Redis-Cache/src/main/java/com/springboot/Application.java ================================================ package com.springboot; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCaching; @SpringBootApplication @EnableCaching public class Application { public static void main(String[] args) { SpringApplication.run(Application.class,args); } } ================================================ FILE: 09.Spring-Boot-Redis-Cache/src/main/java/com/springboot/ApplicationTest.java ================================================ package com.springboot; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import com.springboot.bean.Student; import com.springboot.service.StudentService; @RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest(classes = Application.class) public class ApplicationTest { @Autowired private StudentService studentService; @Test public void test1() throws Exception { Student student1 = this.studentService.queryStudentBySno("001"); System.out.println("学号" + student1.getSno() + "的学生姓名为:" + student1.getName()); Student student2 = this.studentService.queryStudentBySno("001"); System.out.println("学号" + student2.getSno() + "的学生姓名为:" + student2.getName()); } @Test public void test2() throws Exception { Student student1 = this.studentService.queryStudentBySno("001"); System.out.println("学号" + student1.getSno() + "的学生姓名为:" + student1.getName()); student1.setName("康康"); this.studentService.update(student1); Student student2 = this.studentService.queryStudentBySno("001"); System.out.println("学号" + student2.getSno() + "的学生姓名为:" + student2.getName()); } } ================================================ FILE: 09.Spring-Boot-Redis-Cache/src/main/java/com/springboot/bean/Student.java ================================================ package com.springboot.bean; import java.io.Serializable; public class Student implements Serializable{ private static final long serialVersionUID = -339516038496531943L; private String sno; private String name; private String sex; public String getSno() { return sno; } public void setSno(String sno) { this.sno = sno; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } } ================================================ FILE: 09.Spring-Boot-Redis-Cache/src/main/java/com/springboot/config/RedisConfig.java ================================================ package com.springboot.config; import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.CachingConfigurerSupport; import org.springframework.cache.interceptor.KeyGenerator; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.ObjectMapper; @Configuration public class RedisConfig extends CachingConfigurerSupport { // 自定义缓存key生成策略 @Bean public KeyGenerator keyGenerator() { return new KeyGenerator() { @Override public Object generate(Object target, java.lang.reflect.Method method, Object... params) { StringBuffer sb = new StringBuffer(); sb.append(target.getClass().getName()); sb.append(method.getName()); for (Object obj : params) { sb.append(obj.toString()); } return sb.toString(); } }; } // 缓存管理器 @Bean public CacheManager cacheManager(@SuppressWarnings("rawtypes") RedisTemplate redisTemplate) { RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate); // 设置缓存过期时间 cacheManager.setDefaultExpiration(10000); return cacheManager; } @Bean public RedisTemplate redisTemplate(RedisConnectionFactory factory) { StringRedisTemplate template = new StringRedisTemplate(factory); setSerializer(template);// 设置序列化工具 template.afterPropertiesSet(); return template; } private void setSerializer(StringRedisTemplate template) { @SuppressWarnings({ "rawtypes", "unchecked" }) Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(om); template.setValueSerializer(jackson2JsonRedisSerializer); } } ================================================ FILE: 09.Spring-Boot-Redis-Cache/src/main/java/com/springboot/mapper/StudentMapper.java ================================================ package com.springboot.mapper; import org.apache.ibatis.annotations.Delete; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Result; import org.apache.ibatis.annotations.Results; import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.Update; import org.springframework.cache.annotation.CacheConfig; import com.springboot.bean.Student; @Mapper @CacheConfig(cacheNames = "student") public interface StudentMapper { @Update("update student set sname=#{name},ssex=#{sex} where sno=#{sno}") int update(Student student); @Delete("delete from student where sno=#{sno}") void deleteStudentBySno(String sno); @Select("select * from student where sno=#{sno}") @Results(id = "student", value = { @Result(property = "sno", column = "sno", javaType = String.class), @Result(property = "name", column = "sname", javaType = String.class), @Result(property = "sex", column = "ssex", javaType = String.class) }) Student queryStudentBySno(String sno); } ================================================ FILE: 09.Spring-Boot-Redis-Cache/src/main/java/com/springboot/service/StudentService.java ================================================ package com.springboot.service; import org.springframework.cache.annotation.CacheConfig; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.CachePut; import org.springframework.cache.annotation.Cacheable; import com.springboot.bean.Student; @CacheConfig(cacheNames = "student") public interface StudentService { @CachePut(key = "#p0.sno") Student update(Student student); @CacheEvict(key = "#p0", allEntries = true) void deleteStudentBySno(String sno); @Cacheable(key = "#p0") Student queryStudentBySno(String sno); } ================================================ FILE: 09.Spring-Boot-Redis-Cache/src/main/java/com/springboot/service/impl/StudentServiceImpl.java ================================================ package com.springboot.service.impl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; import com.springboot.bean.Student; import com.springboot.mapper.StudentMapper; import com.springboot.service.StudentService; @Repository("studentService") public class StudentServiceImpl implements StudentService{ @Autowired private StudentMapper studentMapper; @Override public Student update(Student student) { this.studentMapper.update(student); return this.studentMapper.queryStudentBySno(student.getSno()); } @Override public void deleteStudentBySno(String sno) { this.studentMapper.deleteStudentBySno(sno); } @Override public Student queryStudentBySno(String sno) { return this.studentMapper.queryStudentBySno(sno); } } ================================================ FILE: 09.Spring-Boot-Redis-Cache/src/main/resources/application.yml ================================================ server: context-path: /web spring: datasource: druid: # 数据库访问配置, 使用druid数据源 type: com.alibaba.druid.pool.DruidDataSource driver-class-name: oracle.jdbc.driver.OracleDriver url: jdbc:oracle:thin:@localhost:1521:ORCL username: test password: 123456 # 连接池配置 initial-size: 5 min-idle: 5 max-active: 20 # 连接等待超时时间 max-wait: 30000 # 配置检测可以关闭的空闲连接间隔时间 time-between-eviction-runs-millis: 60000 # 配置连接在池中的最小生存时间 min-evictable-idle-time-millis: 300000 validation-query: select '1' from dual test-while-idle: true test-on-borrow: false test-on-return: false # 打开PSCache,并且指定每个连接上PSCache的大小 pool-prepared-statements: true max-open-prepared-statements: 20 max-pool-prepared-statement-per-connection-size: 20 # 配置监控统计拦截的filters, 去掉后监控界面sql无法统计, 'wall'用于防火墙 filters: stat,wall # Spring监控AOP切入点,如x.y.z.service.*,配置多个英文逗号分隔 aop-patterns: com.springboot.servie.* # WebStatFilter配置 web-stat-filter: enabled: true # 添加过滤规则 url-pattern: /* # 忽略过滤的格式 exclusions: '*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*' # StatViewServlet配置 stat-view-servlet: enabled: true # 访问路径为/druid时,跳转到StatViewServlet url-pattern: /druid/* # 是否能够重置数据 reset-enable: false # 需要账号密码才能访问控制台 login-username: druid login-password: druid123 # IP白名单 # allow: 127.0.0.1 # IP黑名单(共同存在时,deny优先于allow) # deny: 192.168.1.218 # 配置StatFilter filter: stat: log-slow-sql: true redis: # Redis数据库索引(默认为0) database: 0 # Redis服务器地址 host: localhost # Redis服务器连接端口 port: 6379 pool: # 连接池最大连接数(使用负值表示没有限制) max-active: 8 # 连接池最大阻塞等待时间(使用负值表示没有限制) max-wait: -1 # 连接池中的最大空闲连接 max-idle: 8 # 连接池中的最小空闲连接 min-idle: 0 # 连接超时时间(毫秒) timeout: 0 logging: level: com: springboot: mapper: debug ================================================ FILE: 09.Spring-Boot-Redis-Cache/src/main/resources/init.sql ================================================ CREATE TABLE STUDENT ( SNO VARCHAR2(3 BYTE) NOT NULL , SNAME VARCHAR2(9 BYTE) NOT NULL , SSEX CHAR(2 BYTE) NOT NULL ); INSERT INTO STUDENT VALUES ('001', 'KangKang', 'M '); INSERT INTO STUDENT VALUES ('002', 'Mike', 'M '); INSERT INTO STUDENT VALUES ('003', 'Jane', 'F '); ================================================ FILE: 10.Spring-Boot-Ehcache-Cache/pom.xml ================================================ 4.0.0 com.springboot Spring-Boot-Ehcache-Cache 0.0.1-SNAPSHOT jar demo Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.9.RELEASE UTF-8 UTF-8 1.7 org.springframework.boot spring-boot-starter-web org.mybatis.spring.boot mybatis-spring-boot-starter 1.3.1 org.springframework.boot spring-boot-starter-test test org.springframework.boot spring-boot-starter-cache net.sf.ehcache ehcache com.oracle ojdbc6 6.0 com.alibaba druid-spring-boot-starter 1.1.6 org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 10.Spring-Boot-Ehcache-Cache/src/main/java/com/springboot/Application.java ================================================ package com.springboot; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCaching; @SpringBootApplication @EnableCaching public class Application { public static void main(String[] args) { SpringApplication.run(Application.class,args); } } ================================================ FILE: 10.Spring-Boot-Ehcache-Cache/src/main/java/com/springboot/ApplicationTest.java ================================================ package com.springboot; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.cache.CacheManager; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import com.springboot.bean.Student; import com.springboot.service.StudentService; @RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest(classes = Application.class) public class ApplicationTest { @Autowired private StudentService studentService; @Test public void test1() throws Exception { Student student1 = this.studentService.queryStudentBySno("001"); System.out.println("学号" + student1.getSno() + "的学生姓名为:" + student1.getName()); Student student2 = this.studentService.queryStudentBySno("001"); System.out.println("学号" + student2.getSno() + "的学生姓名为:" + student2.getName()); } @Test public void test2() throws Exception { Student student1 = this.studentService.queryStudentBySno("001"); System.out.println("学号" + student1.getSno() + "的学生姓名为:" + student1.getName()); student1.setName("康康"); this.studentService.update(student1); Student student2 = this.studentService.queryStudentBySno("001"); System.out.println("学号" + student2.getSno() + "的学生姓名为:" + student2.getName()); } } ================================================ FILE: 10.Spring-Boot-Ehcache-Cache/src/main/java/com/springboot/bean/Student.java ================================================ package com.springboot.bean; import java.io.Serializable; public class Student implements Serializable{ private static final long serialVersionUID = -339516038496531943L; private String sno; private String name; private String sex; public String getSno() { return sno; } public void setSno(String sno) { this.sno = sno; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } } ================================================ FILE: 10.Spring-Boot-Ehcache-Cache/src/main/java/com/springboot/mapper/StudentMapper.java ================================================ package com.springboot.mapper; import org.apache.ibatis.annotations.Delete; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Result; import org.apache.ibatis.annotations.Results; import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.Update; import com.springboot.bean.Student; @Mapper public interface StudentMapper { @Update("update student set sname=#{name},ssex=#{sex} where sno=#{sno}") int update(Student student); @Delete("delete from student where sno=#{sno}") void deleteStudentBySno(String sno); @Select("select * from student where sno=#{sno}") @Results(id = "student", value = { @Result(property = "sno", column = "sno", javaType = String.class), @Result(property = "name", column = "sname", javaType = String.class), @Result(property = "sex", column = "ssex", javaType = String.class) }) Student queryStudentBySno(String sno); } ================================================ FILE: 10.Spring-Boot-Ehcache-Cache/src/main/java/com/springboot/service/StudentService.java ================================================ package com.springboot.service; import org.springframework.cache.annotation.CacheConfig; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.CachePut; import org.springframework.cache.annotation.Cacheable; import com.springboot.bean.Student; @CacheConfig(cacheNames = "student") public interface StudentService { @CachePut(key = "#p0.sno") Student update(Student student); @CacheEvict(key = "#p0", allEntries = true) void deleteStudentBySno(String sno); @Cacheable(key = "#p0") Student queryStudentBySno(String sno); } ================================================ FILE: 10.Spring-Boot-Ehcache-Cache/src/main/java/com/springboot/service/impl/StudentServiceImpl.java ================================================ package com.springboot.service.impl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; import com.springboot.bean.Student; import com.springboot.mapper.StudentMapper; import com.springboot.service.StudentService; @Repository("studentService") public class StudentServiceImpl implements StudentService{ @Autowired private StudentMapper studentMapper; @Override public Student update(Student student) { this.studentMapper.update(student); return this.studentMapper.queryStudentBySno(student.getSno()); } @Override public void deleteStudentBySno(String sno) { this.studentMapper.deleteStudentBySno(sno); } @Override public Student queryStudentBySno(String sno) { return this.studentMapper.queryStudentBySno(sno); } } ================================================ FILE: 10.Spring-Boot-Ehcache-Cache/src/main/resources/application.yml ================================================ server: context-path: /web spring: datasource: druid: # 数据库访问配置, 使用druid数据源 type: com.alibaba.druid.pool.DruidDataSource driver-class-name: oracle.jdbc.driver.OracleDriver url: jdbc:oracle:thin:@localhost:1521:ORCL username: test password: 123456 # 连接池配置 initial-size: 5 min-idle: 5 max-active: 20 # 连接等待超时时间 max-wait: 30000 # 配置检测可以关闭的空闲连接间隔时间 time-between-eviction-runs-millis: 60000 # 配置连接在池中的最小生存时间 min-evictable-idle-time-millis: 300000 validation-query: select '1' from dual test-while-idle: true test-on-borrow: false test-on-return: false # 打开PSCache,并且指定每个连接上PSCache的大小 pool-prepared-statements: true max-open-prepared-statements: 20 max-pool-prepared-statement-per-connection-size: 20 # 配置监控统计拦截的filters, 去掉后监控界面sql无法统计, 'wall'用于防火墙 filters: stat,wall # Spring监控AOP切入点,如x.y.z.service.*,配置多个英文逗号分隔 aop-patterns: com.springboot.servie.* # WebStatFilter配置 web-stat-filter: enabled: true # 添加过滤规则 url-pattern: /* # 忽略过滤的格式 exclusions: '*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*' # StatViewServlet配置 stat-view-servlet: enabled: true # 访问路径为/druid时,跳转到StatViewServlet url-pattern: /druid/* # 是否能够重置数据 reset-enable: false # 需要账号密码才能访问控制台 login-username: druid login-password: druid123 # IP白名单 # allow: 127.0.0.1 # IP黑名单(共同存在时,deny优先于allow) # deny: 192.168.1.218 # 配置StatFilter filter: stat: log-slow-sql: true cache: ehcache: config: 'classpath:ehcache.xml' logging: level: com: springboot: mapper: debug ================================================ FILE: 10.Spring-Boot-Ehcache-Cache/src/main/resources/ehcache.xml ================================================ ================================================ FILE: 10.Spring-Boot-Ehcache-Cache/src/main/resources/init.sql ================================================ CREATE TABLE STUDENT ( SNO VARCHAR2(3 BYTE) NOT NULL , SNAME VARCHAR2(9 BYTE) NOT NULL , SSEX CHAR(2 BYTE) NOT NULL ); INSERT INTO STUDENT VALUES ('001', 'KangKang', 'M '); INSERT INTO STUDENT VALUES ('002', 'Mike', 'M '); INSERT INTO STUDENT VALUES ('003', 'Jane', 'F '); ================================================ FILE: 11.Spring-Boot-Shiro-Authentication/pom.xml ================================================ 4.0.0 com.springboot Spring-Boot-Shiro-Authentication 0.0.1-SNAPSHOT jar demo Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.9.RELEASE UTF-8 UTF-8 1.7 3.0.2.RELEASE 2.0.1 org.springframework.boot spring-boot-starter-web org.mybatis.spring.boot mybatis-spring-boot-starter 1.3.1 org.springframework.boot spring-boot-starter-thymeleaf org.apache.shiro shiro-spring 1.4.0 com.oracle ojdbc6 6.0 com.alibaba druid-spring-boot-starter 1.1.6 org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 11.Spring-Boot-Shiro-Authentication/src/main/java/com/springboot/Application.java ================================================ package com.springboot; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class,args); } } ================================================ FILE: 11.Spring-Boot-Shiro-Authentication/src/main/java/com/springboot/config/ShiroConfig.java ================================================ package com.springboot.config; import java.util.LinkedHashMap; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import com.springboot.shiro.ShiroRealm; @Configuration public class ShiroConfig { @Bean public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager); shiroFilterFactoryBean.setLoginUrl("/login"); shiroFilterFactoryBean.setSuccessUrl("/index"); shiroFilterFactoryBean.setUnauthorizedUrl("/403"); LinkedHashMap filterChainDefinitionMap = new LinkedHashMap<>(); filterChainDefinitionMap.put("/css/**", "anon"); filterChainDefinitionMap.put("/js/**", "anon"); filterChainDefinitionMap.put("/fonts/**", "anon"); filterChainDefinitionMap.put("/img/**", "anon"); filterChainDefinitionMap.put("/druid/**", "anon"); filterChainDefinitionMap.put("/logout", "logout"); filterChainDefinitionMap.put("/", "anon"); filterChainDefinitionMap.put("/**", "authc"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } @Bean public SecurityManager securityManager(){ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(shiroRealm()); return securityManager; } @Bean public ShiroRealm shiroRealm(){ ShiroRealm shiroRealm = new ShiroRealm(); return shiroRealm; } } ================================================ FILE: 11.Spring-Boot-Shiro-Authentication/src/main/java/com/springboot/controller/LoginController.java ================================================ package com.springboot.controller; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.LockedAccountException; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.subject.Subject; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import com.springboot.pojo.ResponseBo; import com.springboot.pojo.User; import com.springboot.util.MD5Utils; @Controller public class LoginController { @GetMapping("/login") public String login() { return "login"; } @PostMapping("/login") @ResponseBody public ResponseBo login(String username, String password) { password = MD5Utils.encrypt(username, password); UsernamePasswordToken token = new UsernamePasswordToken(username, password); Subject subject = SecurityUtils.getSubject(); try { subject.login(token); return ResponseBo.ok(); } catch (UnknownAccountException e) { return ResponseBo.error(e.getMessage()); } catch (IncorrectCredentialsException e) { return ResponseBo.error(e.getMessage()); } catch (LockedAccountException e) { return ResponseBo.error(e.getMessage()); } catch (AuthenticationException e) { return ResponseBo.error("认证失败!"); } } @RequestMapping("/") public String redirectIndex() { return "redirect:/index"; } @RequestMapping("/index") public String index(Model model) { User user = (User) SecurityUtils.getSubject().getPrincipal(); model.addAttribute("user", user); return "index"; } } ================================================ FILE: 11.Spring-Boot-Shiro-Authentication/src/main/java/com/springboot/dao/UserMapper.java ================================================ package com.springboot.dao; import org.apache.ibatis.annotations.Mapper; import com.springboot.pojo.User; @Mapper public interface UserMapper { User findByUserName(String userName); } ================================================ FILE: 11.Spring-Boot-Shiro-Authentication/src/main/java/com/springboot/pojo/ResponseBo.java ================================================ package com.springboot.pojo; import java.util.HashMap; import java.util.Map; public class ResponseBo extends HashMap{ private static final long serialVersionUID = 1L; public ResponseBo() { put("code", 0); put("msg", "操作成功"); } public static ResponseBo error() { return error(1, "操作失败"); } public static ResponseBo error(String msg) { return error(500, msg); } public static ResponseBo error(int code, String msg) { ResponseBo ResponseBo = new ResponseBo(); ResponseBo.put("code", code); ResponseBo.put("msg", msg); return ResponseBo; } public static ResponseBo ok(String msg) { ResponseBo ResponseBo = new ResponseBo(); ResponseBo.put("msg", msg); return ResponseBo; } public static ResponseBo ok(Map map) { ResponseBo ResponseBo = new ResponseBo(); ResponseBo.putAll(map); return ResponseBo; } public static ResponseBo ok() { return new ResponseBo(); } @Override public ResponseBo put(String key, Object value) { super.put(key, value); return this; } } ================================================ FILE: 11.Spring-Boot-Shiro-Authentication/src/main/java/com/springboot/pojo/User.java ================================================ package com.springboot.pojo; import java.io.Serializable; import java.util.Date; public class User implements Serializable{ private static final long serialVersionUID = -5440372534300871944L; private Integer id; private String userName; private String password; private Date createTime; private String status; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Date getCreateTime() { return createTime; } public void setCreateTime(Date createTime) { this.createTime = createTime; } public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } } ================================================ FILE: 11.Spring-Boot-Shiro-Authentication/src/main/java/com/springboot/shiro/ShiroRealm.java ================================================ package com.springboot.shiro; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.LockedAccountException; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.springframework.beans.factory.annotation.Autowired; import com.springboot.dao.UserMapper; import com.springboot.pojo.User; public class ShiroRealm extends AuthorizingRealm { @Autowired private UserMapper userMapper; /** * 获取用户角色和权限 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) { return null; } /** * 登录认证 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { String userName = (String) token.getPrincipal(); String password = new String((char[]) token.getCredentials()); System.out.println("用户" + userName + "认证-----ShiroRealm.doGetAuthenticationInfo"); User user = userMapper.findByUserName(userName); if (user == null) { throw new UnknownAccountException("用户名或密码错误!"); } if (!password.equals(user.getPassword())) { throw new IncorrectCredentialsException("用户名或密码错误!"); } if (user.getStatus().equals("0")) { throw new LockedAccountException("账号已被锁定,请联系管理员!"); } SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, password, getName()); return info; } } ================================================ FILE: 11.Spring-Boot-Shiro-Authentication/src/main/java/com/springboot/util/MD5Utils.java ================================================ package com.springboot.util; import org.apache.shiro.crypto.hash.SimpleHash; import org.apache.shiro.util.ByteSource; public class MD5Utils { private static final String SALT = "mrbird"; private static final String ALGORITH_NAME = "md5"; private static final int HASH_ITERATIONS = 2; public static String encrypt(String pswd) { String newPassword = new SimpleHash(ALGORITH_NAME, pswd, ByteSource.Util.bytes(SALT), HASH_ITERATIONS).toHex(); return newPassword; } public static String encrypt(String username, String pswd) { String newPassword = new SimpleHash(ALGORITH_NAME, pswd, ByteSource.Util.bytes(username + SALT), HASH_ITERATIONS).toHex(); return newPassword; } public static void main(String[] args) { System.out.println(MD5Utils.encrypt("test", "123456")); } } ================================================ FILE: 11.Spring-Boot-Shiro-Authentication/src/main/resources/application.yml ================================================ server: context-path: /web spring: datasource: druid: # 数据库访问配置, 使用druid数据源 type: com.alibaba.druid.pool.DruidDataSource driver-class-name: oracle.jdbc.driver.OracleDriver url: jdbc:oracle:thin:@localhost:1521:ORCL username: test password: 123456 # 连接池配置 initial-size: 5 min-idle: 5 max-active: 20 # 连接等待超时时间 max-wait: 30000 # 配置检测可以关闭的空闲连接间隔时间 time-between-eviction-runs-millis: 60000 # 配置连接在池中的最小生存时间 min-evictable-idle-time-millis: 300000 validation-query: select '1' from dual test-while-idle: true test-on-borrow: false test-on-return: false # 打开PSCache,并且指定每个连接上PSCache的大小 pool-prepared-statements: true max-open-prepared-statements: 20 max-pool-prepared-statement-per-connection-size: 20 # 配置监控统计拦截的filters, 去掉后监控界面sql无法统计, 'wall'用于防火墙 filters: stat # Spring监控AOP切入点,如x.y.z.service.*,配置多个英文逗号分隔 aop-patterns: com.springboot.servie.* # WebStatFilter配置 web-stat-filter: enabled: true # 添加过滤规则 url-pattern: /* # 忽略过滤的格式 exclusions: '*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*' # StatViewServlet配置 stat-view-servlet: enabled: true # 访问路径为/druid时,跳转到StatViewServlet url-pattern: /druid/* # 是否能够重置数据 reset-enable: false # 需要账号密码才能访问控制台 login-username: druid login-password: druid123 # IP白名单 # allow: 127.0.0.1 # IP黑名单(共同存在时,deny优先于allow) # deny: 192.168.1.218 # 配置StatFilter filter: stat: log-slow-sql: true thymeleaf: cache: false mybatis: # type-aliases扫描路径 type-aliases-package: com.springboot.pojo # mapper xml实现扫描路径 mapper-locations: classpath:mapper/*.xml property: order: BEFORE ================================================ FILE: 11.Spring-Boot-Shiro-Authentication/src/main/resources/init.sql ================================================ -- ---------------------------- -- Table structure for T_USER -- ---------------------------- CREATE TABLE T_USER ( ID NUMBER NOT NULL , USERNAME VARCHAR2(20 BYTE) NOT NULL , PASSWD VARCHAR2(128 BYTE) NOT NULL , CREATE_TIME DATE NULL , STATUS CHAR(1 BYTE) NOT NULL ); COMMENT ON COLUMN T_USER.USERNAME IS '用户名'; COMMENT ON COLUMN T_USER.PASSWD IS '密码'; COMMENT ON COLUMN T_USER.CREATE_TIME IS '创建时间'; COMMENT ON COLUMN T_USER.STATUS IS '是否有效 1:有效 0:锁定'; -- ---------------------------- -- Records of T_USER -- ---------------------------- INSERT INTO T_USER VALUES ('2', 'test', '7a38c13ec5e9310aed731de58bbc4214', TO_DATE('2017-11-19 17:20:21', 'YYYY-MM-DD HH24:MI:SS'), '0'); INSERT INTO T_USER VALUES ('1', 'mrbird', '42ee25d1e43e9f57119a00d0a39e5250', TO_DATE('2017-11-19 10:52:48', 'YYYY-MM-DD HH24:MI:SS'), '1'); -- ---------------------------- -- Primary Key structure for table T_USER -- ---------------------------- ALTER TABLE T_USER ADD PRIMARY KEY (ID); ================================================ FILE: 11.Spring-Boot-Shiro-Authentication/src/main/resources/mapper/UserMapper.xml ================================================ ================================================ FILE: 11.Spring-Boot-Shiro-Authentication/src/main/resources/static/css/login.css ================================================ .login-page { width: 360px; padding: 8% 0 0; margin: auto; } .form { position: relative; z-index: 1; background: #ffffff; max-width: 360px; margin: 0 auto 100px; padding: 45px; text-align: center; box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.2), 0 5px 5px 0 rgba(0, 0, 0, 0.24); } .form input { outline: 0; background: #f2f2f2; width: 100%; border: 0; margin: 0 0 15px; padding: 15px; box-sizing: border-box; font-size: 14px; } .form button { text-transform: uppercase; outline: 0; background: #4caf50; width: 100%; border: 0; padding: 15px; color: #ffffff; font-size: 14px; -webkit-transition: all 0.3 ease; transition: all 0.3 ease; cursor: pointer; } .form button:hover, .form button:active, .form button:focus { background: #43a047; } .form .message { margin: 15px 0 0; color: #b3b3b3; font-size: 12px; } .form .message a { color: #4caf50; text-decoration: none; } .form .register-form { display: none; } .container { position: relative; z-index: 1; max-width: 300px; margin: 0 auto; } .container:before, .container:after { content: ""; display: block; clear: both; } .container .info { margin: 50px auto; text-align: center; } .container .info h1 { margin: 0 0 15px; padding: 0; font-size: 36px; font-weight: 300; color: #1a1a1a; } .container .info span { color: #4d4d4d; font-size: 12px; } .container .info span a { color: #000000; text-decoration: none; } .container .info span .fa { color: #ef3b3a; } body { background: #76b852; /* fallback for old browsers */ background: -webkit-linear-gradient(right, #76b852, #8dc26f); background: -moz-linear-gradient(right, #76b852, #8dc26f); background: -o-linear-gradient(right, #76b852, #8dc26f); background: linear-gradient(to left, #76b852, #8dc26f); font-family: Lato,"PingFang SC","Microsoft YaHei",sans-serif; } ================================================ FILE: 11.Spring-Boot-Shiro-Authentication/src/main/resources/templates/index.html ================================================ 首页

你好![[${user.userName}]]

注销 ================================================ FILE: 11.Spring-Boot-Shiro-Authentication/src/main/resources/templates/login.html ================================================ 登录 ================================================ FILE: 12.Spring-Boot-Shiro-RememberMe/pom.xml ================================================ 4.0.0 com.springboot Spring-Boot-Shiro-RememberMe 0.0.1-SNAPSHOT jar demo Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.9.RELEASE UTF-8 UTF-8 1.7 3.0.2.RELEASE 2.0.1 org.springframework.boot spring-boot-starter-web org.mybatis.spring.boot mybatis-spring-boot-starter 1.3.1 org.springframework.boot spring-boot-starter-thymeleaf org.apache.shiro shiro-spring 1.4.0 com.oracle ojdbc6 6.0 com.alibaba druid-spring-boot-starter 1.1.6 org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 12.Spring-Boot-Shiro-RememberMe/src/main/java/com/springboot/Application.java ================================================ package com.springboot; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class,args); } } ================================================ FILE: 12.Spring-Boot-Shiro-RememberMe/src/main/java/com/springboot/config/ShiroConfig.java ================================================ package com.springboot.config; import java.util.LinkedHashMap; import org.apache.shiro.codec.Base64; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.spring.LifecycleBeanPostProcessor; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.CookieRememberMeManager; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.apache.shiro.web.servlet.SimpleCookie; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import com.springboot.shiro.ShiroRealm; @Configuration public class ShiroConfig { @Bean public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager); shiroFilterFactoryBean.setLoginUrl("/login"); shiroFilterFactoryBean.setSuccessUrl("/index"); shiroFilterFactoryBean.setUnauthorizedUrl("/403"); LinkedHashMap filterChainDefinitionMap = new LinkedHashMap<>(); filterChainDefinitionMap.put("/css/**", "anon"); filterChainDefinitionMap.put("/js/**", "anon"); filterChainDefinitionMap.put("/fonts/**", "anon"); filterChainDefinitionMap.put("/img/**", "anon"); filterChainDefinitionMap.put("/druid/**", "anon"); filterChainDefinitionMap.put("/logout", "logout"); filterChainDefinitionMap.put("/", "anon"); filterChainDefinitionMap.put("/**", "user"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } @Bean public SecurityManager securityManager(){ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(shiroRealm()); securityManager.setRememberMeManager(rememberMeManager()); return securityManager; } @Bean(name = "lifecycleBeanPostProcessor") public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { return new LifecycleBeanPostProcessor(); } @Bean public ShiroRealm shiroRealm(){ ShiroRealm shiroRealm = new ShiroRealm(); return shiroRealm; } /** * cookie对象 * @return */ public SimpleCookie rememberMeCookie() { // 设置cookie名称,对应login.html页面的 SimpleCookie cookie = new SimpleCookie("rememberMe"); // 设置cookie的过期时间,单位为秒,这里为一天 cookie.setMaxAge(86400); return cookie; } /** * cookie管理对象 * @return */ public CookieRememberMeManager rememberMeManager() { CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager(); cookieRememberMeManager.setCookie(rememberMeCookie()); // rememberMe cookie加密的密钥 cookieRememberMeManager.setCipherKey(Base64.decode("3AvVhmFLUs0KTA3Kprsdag==")); return cookieRememberMeManager; } } ================================================ FILE: 12.Spring-Boot-Shiro-RememberMe/src/main/java/com/springboot/controller/LoginController.java ================================================ package com.springboot.controller; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.LockedAccountException; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.subject.Subject; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import com.springboot.pojo.ResponseBo; import com.springboot.pojo.User; import com.springboot.util.MD5Utils; @Controller public class LoginController { @GetMapping("/login") public String login() { return "login"; } @PostMapping("/login") @ResponseBody public ResponseBo login(String username, String password, Boolean rememberMe) { password = MD5Utils.encrypt(username, password); UsernamePasswordToken token = new UsernamePasswordToken(username, password, rememberMe); Subject subject = SecurityUtils.getSubject(); try { subject.login(token); return ResponseBo.ok(); } catch (UnknownAccountException e) { return ResponseBo.error(e.getMessage()); } catch (IncorrectCredentialsException e) { return ResponseBo.error(e.getMessage()); } catch (LockedAccountException e) { return ResponseBo.error(e.getMessage()); } catch (AuthenticationException e) { return ResponseBo.error("认证失败!"); } } @RequestMapping("/") public String redirectIndex() { return "redirect:/index"; } @RequestMapping("/index") public String index(Model model) { User user = (User) SecurityUtils.getSubject().getPrincipal(); model.addAttribute("user", user); return "index"; } } ================================================ FILE: 12.Spring-Boot-Shiro-RememberMe/src/main/java/com/springboot/dao/UserMapper.java ================================================ package com.springboot.dao; import org.apache.ibatis.annotations.Mapper; import com.springboot.pojo.User; @Mapper public interface UserMapper { User findByUserName(String userName); } ================================================ FILE: 12.Spring-Boot-Shiro-RememberMe/src/main/java/com/springboot/pojo/ResponseBo.java ================================================ package com.springboot.pojo; import java.util.HashMap; import java.util.Map; public class ResponseBo extends HashMap{ private static final long serialVersionUID = 1L; public ResponseBo() { put("code", 0); put("msg", "操作成功"); } public static ResponseBo error() { return error(1, "操作失败"); } public static ResponseBo error(String msg) { return error(500, msg); } public static ResponseBo error(int code, String msg) { ResponseBo ResponseBo = new ResponseBo(); ResponseBo.put("code", code); ResponseBo.put("msg", msg); return ResponseBo; } public static ResponseBo ok(String msg) { ResponseBo ResponseBo = new ResponseBo(); ResponseBo.put("msg", msg); return ResponseBo; } public static ResponseBo ok(Map map) { ResponseBo ResponseBo = new ResponseBo(); ResponseBo.putAll(map); return ResponseBo; } public static ResponseBo ok() { return new ResponseBo(); } @Override public ResponseBo put(String key, Object value) { super.put(key, value); return this; } } ================================================ FILE: 12.Spring-Boot-Shiro-RememberMe/src/main/java/com/springboot/pojo/User.java ================================================ package com.springboot.pojo; import java.io.Serializable; import java.util.Date; public class User implements Serializable{ private static final long serialVersionUID = -5440372534300871944L; private Integer id; private String userName; private String password; private Date createTime; private String status; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Date getCreateTime() { return createTime; } public void setCreateTime(Date createTime) { this.createTime = createTime; } public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } } ================================================ FILE: 12.Spring-Boot-Shiro-RememberMe/src/main/java/com/springboot/shiro/ShiroRealm.java ================================================ package com.springboot.shiro; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.LockedAccountException; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.springframework.beans.factory.annotation.Autowired; import com.springboot.dao.UserMapper; import com.springboot.pojo.User; public class ShiroRealm extends AuthorizingRealm { @Autowired private UserMapper userMapper; /** * 获取用户角色和权限 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) { return null; } /** * 登录认证 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { String userName = (String) token.getPrincipal(); String password = new String((char[]) token.getCredentials()); System.out.println("用户" + userName + "认证-----ShiroRealm.doGetAuthenticationInfo"); User user = userMapper.findByUserName(userName); if (user == null) { throw new UnknownAccountException("用户名或密码错误!"); } if (!password.equals(user.getPassword())) { throw new IncorrectCredentialsException("用户名或密码错误!"); } if (user.getStatus().equals("0")) { throw new LockedAccountException("账号已被锁定,请联系管理员!"); } SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, password, getName()); return info; } } ================================================ FILE: 12.Spring-Boot-Shiro-RememberMe/src/main/java/com/springboot/util/MD5Utils.java ================================================ package com.springboot.util; import org.apache.shiro.crypto.hash.SimpleHash; import org.apache.shiro.util.ByteSource; public class MD5Utils { private static final String SALT = "mrbird"; private static final String ALGORITH_NAME = "md5"; private static final int HASH_ITERATIONS = 2; public static String encrypt(String pswd) { String newPassword = new SimpleHash(ALGORITH_NAME, pswd, ByteSource.Util.bytes(SALT), HASH_ITERATIONS).toHex(); return newPassword; } public static String encrypt(String username, String pswd) { String newPassword = new SimpleHash(ALGORITH_NAME, pswd, ByteSource.Util.bytes(username + SALT), HASH_ITERATIONS).toHex(); return newPassword; } public static void main(String[] args) { System.out.println(MD5Utils.encrypt("test", "123456")); } } ================================================ FILE: 12.Spring-Boot-Shiro-RememberMe/src/main/resources/application.yml ================================================ server: context-path: /web spring: datasource: druid: # 数据库访问配置, 使用druid数据源 type: com.alibaba.druid.pool.DruidDataSource driver-class-name: oracle.jdbc.driver.OracleDriver url: jdbc:oracle:thin:@localhost:1521:ORCL username: test password: 123456 # 连接池配置 initial-size: 5 min-idle: 5 max-active: 20 # 连接等待超时时间 max-wait: 30000 # 配置检测可以关闭的空闲连接间隔时间 time-between-eviction-runs-millis: 60000 # 配置连接在池中的最小生存时间 min-evictable-idle-time-millis: 300000 validation-query: select '1' from dual test-while-idle: true test-on-borrow: false test-on-return: false # 打开PSCache,并且指定每个连接上PSCache的大小 pool-prepared-statements: true max-open-prepared-statements: 20 max-pool-prepared-statement-per-connection-size: 20 # 配置监控统计拦截的filters, 去掉后监控界面sql无法统计, 'wall'用于防火墙 filters: stat # Spring监控AOP切入点,如x.y.z.service.*,配置多个英文逗号分隔 aop-patterns: com.springboot.servie.* # WebStatFilter配置 web-stat-filter: enabled: true # 添加过滤规则 url-pattern: /* # 忽略过滤的格式 exclusions: '*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*' # StatViewServlet配置 stat-view-servlet: enabled: true # 访问路径为/druid时,跳转到StatViewServlet url-pattern: /druid/* # 是否能够重置数据 reset-enable: false # 需要账号密码才能访问控制台 login-username: druid login-password: druid123 # IP白名单 # allow: 127.0.0.1 # IP黑名单(共同存在时,deny优先于allow) # deny: 192.168.1.218 # 配置StatFilter filter: stat: log-slow-sql: true thymeleaf: cache: false mybatis: # type-aliases扫描路径 type-aliases-package: com.springboot.pojo # mapper xml实现扫描路径 mapper-locations: classpath:mapper/*.xml property: order: BEFORE ================================================ FILE: 12.Spring-Boot-Shiro-RememberMe/src/main/resources/init.sql ================================================ -- ---------------------------- -- Table structure for T_USER -- ---------------------------- CREATE TABLE T_USER ( ID NUMBER NOT NULL , USERNAME VARCHAR2(20 BYTE) NOT NULL , PASSWD VARCHAR2(128 BYTE) NOT NULL , CREATE_TIME DATE NULL , STATUS CHAR(1 BYTE) NOT NULL ); COMMENT ON COLUMN T_USER.USERNAME IS '用户名'; COMMENT ON COLUMN T_USER.PASSWD IS '密码'; COMMENT ON COLUMN T_USER.CREATE_TIME IS '创建时间'; COMMENT ON COLUMN T_USER.STATUS IS '是否有效 1:有效 0:锁定'; -- ---------------------------- -- Records of T_USER -- ---------------------------- INSERT INTO T_USER VALUES ('2', 'test', '7a38c13ec5e9310aed731de58bbc4214', TO_DATE('2017-11-19 17:20:21', 'YYYY-MM-DD HH24:MI:SS'), '0'); INSERT INTO T_USER VALUES ('1', 'mrbird', '42ee25d1e43e9f57119a00d0a39e5250', TO_DATE('2017-11-19 10:52:48', 'YYYY-MM-DD HH24:MI:SS'), '1'); -- ---------------------------- -- Primary Key structure for table T_USER -- ---------------------------- ALTER TABLE T_USER ADD PRIMARY KEY (ID); ================================================ FILE: 12.Spring-Boot-Shiro-RememberMe/src/main/resources/mapper/UserMapper.xml ================================================ ================================================ FILE: 12.Spring-Boot-Shiro-RememberMe/src/main/resources/static/css/login.css ================================================ .login-page { width: 360px; padding: 8% 0 0; margin: auto; } .form { position: relative; z-index: 1; background: #ffffff; max-width: 360px; margin: 0 auto 100px; padding: 45px; text-align: center; box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.2), 0 5px 5px 0 rgba(0, 0, 0, 0.24); } .form input { outline: 0; background: #f2f2f2; width: 100%; border: 0; margin: 0 0 15px; padding: 15px; box-sizing: border-box; font-size: 14px; } .form button { text-transform: uppercase; outline: 0; background: #4caf50; width: 100%; border: 0; padding: 15px; color: #ffffff; font-size: 14px; -webkit-transition: all 0.3 ease; transition: all 0.3 ease; cursor: pointer; } .form button:hover, .form button:active, .form button:focus { background: #43a047; } .form .message { margin: 15px 0 0; color: #b3b3b3; font-size: 12px; } .form .message a { color: #4caf50; text-decoration: none; } .form .register-form { display: none; } .form p { text-align: left; margin: 0; font-size: 13px; } .form p input { width: auto; margin-right: 10px; } .container { position: relative; z-index: 1; max-width: 300px; margin: 0 auto; } .container:before, .container:after { content: ""; display: block; clear: both; } .container .info { margin: 50px auto; text-align: center; } .container .info h1 { margin: 0 0 15px; padding: 0; font-size: 36px; font-weight: 300; color: #1a1a1a; } .container .info span { color: #4d4d4d; font-size: 12px; } .container .info span a { color: #000000; text-decoration: none; } .container .info span .fa { color: #ef3b3a; } body { background: #76b852; /* fallback for old browsers */ background: -webkit-linear-gradient(right, #76b852, #8dc26f); background: -moz-linear-gradient(right, #76b852, #8dc26f); background: -o-linear-gradient(right, #76b852, #8dc26f); background: linear-gradient(to left, #76b852, #8dc26f); font-family: Lato,"PingFang SC","Microsoft YaHei",sans-serif; } ================================================ FILE: 12.Spring-Boot-Shiro-RememberMe/src/main/resources/templates/index.html ================================================ 首页

你好![[${user.userName}]]

注销 ================================================ FILE: 12.Spring-Boot-Shiro-RememberMe/src/main/resources/templates/login.html ================================================ 登录 ================================================ FILE: 13.Spring-Boot-Shiro-Authorization/pom.xml ================================================ 4.0.0 com.springboot Spring-Boot-Shiro-Authorization 0.0.1-SNAPSHOT jar demo Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.9.RELEASE UTF-8 UTF-8 1.7 3.0.2.RELEASE 2.0.1 org.springframework.boot spring-boot-starter-web org.mybatis.spring.boot mybatis-spring-boot-starter 1.3.1 org.springframework.boot spring-boot-starter-thymeleaf org.apache.shiro shiro-spring 1.4.0 com.oracle ojdbc6 6.0 com.alibaba druid-spring-boot-starter 1.1.6 org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 13.Spring-Boot-Shiro-Authorization/src/main/java/com/springboot/Application.java ================================================ package com.springboot; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class,args); } } ================================================ FILE: 13.Spring-Boot-Shiro-Authorization/src/main/java/com/springboot/config/ShiroConfig.java ================================================ package com.springboot.config; import java.util.LinkedHashMap; import org.apache.shiro.codec.Base64; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.CookieRememberMeManager; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.apache.shiro.web.servlet.SimpleCookie; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.DependsOn; import com.springboot.shiro.ShiroRealm; @Configuration public class ShiroConfig { @Bean public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager); shiroFilterFactoryBean.setLoginUrl("/login"); shiroFilterFactoryBean.setSuccessUrl("/index"); shiroFilterFactoryBean.setUnauthorizedUrl("/403"); LinkedHashMap filterChainDefinitionMap = new LinkedHashMap<>(); filterChainDefinitionMap.put("/css/**", "anon"); filterChainDefinitionMap.put("/js/**", "anon"); filterChainDefinitionMap.put("/fonts/**", "anon"); filterChainDefinitionMap.put("/img/**", "anon"); filterChainDefinitionMap.put("/druid/**", "anon"); filterChainDefinitionMap.put("/logout", "logout"); filterChainDefinitionMap.put("/", "anon"); filterChainDefinitionMap.put("/**", "user"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } @Bean public SecurityManager securityManager(){ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(shiroRealm()); securityManager.setRememberMeManager(rememberMeManager()); return securityManager; } @Bean public ShiroRealm shiroRealm(){ ShiroRealm shiroRealm = new ShiroRealm(); return shiroRealm; } public SimpleCookie rememberMeCookie() { SimpleCookie cookie = new SimpleCookie("rememberMe"); cookie.setMaxAge(86400); return cookie; } public CookieRememberMeManager rememberMeManager() { CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager(); cookieRememberMeManager.setCookie(rememberMeCookie()); cookieRememberMeManager.setCipherKey(Base64.decode("4AvVhmFLUs0KTA3Kprsdag==")); return cookieRememberMeManager; } @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) { AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); return authorizationAttributeSourceAdvisor; } } ================================================ FILE: 13.Spring-Boot-Shiro-Authorization/src/main/java/com/springboot/controller/LoginController.java ================================================ package com.springboot.controller; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.LockedAccountException; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.subject.Subject; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import com.springboot.pojo.ResponseBo; import com.springboot.pojo.User; import com.springboot.util.MD5Utils; @Controller public class LoginController { @GetMapping("/login") public String login() { return "login"; } @PostMapping("/login") @ResponseBody public ResponseBo login(String username, String password, Boolean rememberMe) { password = MD5Utils.encrypt(username, password); UsernamePasswordToken token = new UsernamePasswordToken(username, password, rememberMe); Subject subject = SecurityUtils.getSubject(); try { subject.login(token); return ResponseBo.ok(); } catch (UnknownAccountException e) { return ResponseBo.error(e.getMessage()); } catch (IncorrectCredentialsException e) { return ResponseBo.error(e.getMessage()); } catch (LockedAccountException e) { return ResponseBo.error(e.getMessage()); } catch (AuthenticationException e) { return ResponseBo.error("认证失败!"); } } @RequestMapping("/") public String redirectIndex() { return "redirect:/index"; } @GetMapping("/403") public String forbid() { return "403"; } @RequestMapping("/index") public String index(Model model) { User user = (User) SecurityUtils.getSubject().getPrincipal(); model.addAttribute("user", user); return "index"; } } ================================================ FILE: 13.Spring-Boot-Shiro-Authorization/src/main/java/com/springboot/controller/UserController.java ================================================ package com.springboot.controller; import org.apache.shiro.authz.annotation.RequiresPermissions; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; @Controller @RequestMapping("/user") public class UserController { @RequiresPermissions("user:user") @RequestMapping("list") public String userList(Model model) { model.addAttribute("value", "获取用户信息"); return "user"; } @RequiresPermissions("user:add") @RequestMapping("add") public String userAdd(Model model) { model.addAttribute("value", "新增用户"); return "user"; } @RequiresPermissions("user:delete") @RequestMapping("delete") public String userDelete(Model model) { model.addAttribute("value", "删除用户"); return "user"; } } ================================================ FILE: 13.Spring-Boot-Shiro-Authorization/src/main/java/com/springboot/dao/UserMapper.java ================================================ package com.springboot.dao; import org.apache.ibatis.annotations.Mapper; import com.springboot.pojo.User; @Mapper public interface UserMapper { User findByUserName(String userName); } ================================================ FILE: 13.Spring-Boot-Shiro-Authorization/src/main/java/com/springboot/dao/UserPermissionMapper.java ================================================ package com.springboot.dao; import java.util.List; import org.apache.ibatis.annotations.Mapper; import com.springboot.pojo.Permission; @Mapper public interface UserPermissionMapper { List findByUserName(String userName); } ================================================ FILE: 13.Spring-Boot-Shiro-Authorization/src/main/java/com/springboot/dao/UserRoleMapper.java ================================================ package com.springboot.dao; import java.util.List; import org.apache.ibatis.annotations.Mapper; import com.springboot.pojo.Role; @Mapper public interface UserRoleMapper { List findByUserName(String userName); } ================================================ FILE: 13.Spring-Boot-Shiro-Authorization/src/main/java/com/springboot/handler/GlobalExceptionHandler.java ================================================ package com.springboot.handler; import org.apache.shiro.authz.AuthorizationException; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; @ControllerAdvice @Order(value = Ordered.HIGHEST_PRECEDENCE) public class GlobalExceptionHandler { @ExceptionHandler(value = AuthorizationException.class) public String handleAuthorizationException() { return "403"; } } ================================================ FILE: 13.Spring-Boot-Shiro-Authorization/src/main/java/com/springboot/pojo/Permission.java ================================================ package com.springboot.pojo; import java.io.Serializable; public class Permission implements Serializable{ private static final long serialVersionUID = 7160557680614732403L; private Integer id; private String url; private String name; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getName() { return name; } public void setName(String name) { this.name = name; } } ================================================ FILE: 13.Spring-Boot-Shiro-Authorization/src/main/java/com/springboot/pojo/ResponseBo.java ================================================ package com.springboot.pojo; import java.util.HashMap; import java.util.Map; public class ResponseBo extends HashMap{ private static final long serialVersionUID = 1L; public ResponseBo() { put("code", 0); put("msg", "操作成功"); } public static ResponseBo error() { return error(1, "操作失败"); } public static ResponseBo error(String msg) { return error(500, msg); } public static ResponseBo error(int code, String msg) { ResponseBo ResponseBo = new ResponseBo(); ResponseBo.put("code", code); ResponseBo.put("msg", msg); return ResponseBo; } public static ResponseBo ok(String msg) { ResponseBo ResponseBo = new ResponseBo(); ResponseBo.put("msg", msg); return ResponseBo; } public static ResponseBo ok(Map map) { ResponseBo ResponseBo = new ResponseBo(); ResponseBo.putAll(map); return ResponseBo; } public static ResponseBo ok() { return new ResponseBo(); } @Override public ResponseBo put(String key, Object value) { super.put(key, value); return this; } } ================================================ FILE: 13.Spring-Boot-Shiro-Authorization/src/main/java/com/springboot/pojo/Role.java ================================================ package com.springboot.pojo; import java.io.Serializable; public class Role implements Serializable{ private static final long serialVersionUID = -227437593919820521L; private Integer id; private String name; private String memo; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getMemo() { return memo; } public void setMemo(String memo) { this.memo = memo; } } ================================================ FILE: 13.Spring-Boot-Shiro-Authorization/src/main/java/com/springboot/pojo/User.java ================================================ package com.springboot.pojo; import java.io.Serializable; import java.util.Date; public class User implements Serializable{ private static final long serialVersionUID = -5440372534300871944L; private Integer id; private String userName; private String password; private Date createTime; private String status; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Date getCreateTime() { return createTime; } public void setCreateTime(Date createTime) { this.createTime = createTime; } public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } } ================================================ FILE: 13.Spring-Boot-Shiro-Authorization/src/main/java/com/springboot/shiro/ShiroRealm.java ================================================ package com.springboot.shiro; import java.util.HashSet; import java.util.List; import java.util.Set; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.LockedAccountException; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.springframework.beans.factory.annotation.Autowired; import com.springboot.dao.UserMapper; import com.springboot.dao.UserPermissionMapper; import com.springboot.dao.UserRoleMapper; import com.springboot.pojo.Permission; import com.springboot.pojo.Role; import com.springboot.pojo.User; public class ShiroRealm extends AuthorizingRealm { @Autowired private UserMapper userMapper; @Autowired private UserRoleMapper userRoleMapper; @Autowired private UserPermissionMapper userPermissionMapper; /** * 获取用户角色和权限 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) { User user = (User) SecurityUtils.getSubject().getPrincipal(); String userName = user.getUserName(); System.out.println("用户" + userName + "获取权限-----ShiroRealm.doGetAuthorizationInfo"); SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(); // 获取用户角色集 List roleList = userRoleMapper.findByUserName(userName); Set roleSet = new HashSet(); for (Role r : roleList) { roleSet.add(r.getName()); } simpleAuthorizationInfo.setRoles(roleSet); // 获取用户权限集 List permissionList = userPermissionMapper.findByUserName(userName); Set permissionSet = new HashSet(); for (Permission p : permissionList) { permissionSet.add(p.getName()); } simpleAuthorizationInfo.setStringPermissions(permissionSet); return simpleAuthorizationInfo; } /** * 登录认证 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { String userName = (String) token.getPrincipal(); String password = new String((char[]) token.getCredentials()); System.out.println("用户" + userName + "认证-----ShiroRealm.doGetAuthenticationInfo"); User user = userMapper.findByUserName(userName); if (user == null) { throw new UnknownAccountException("用户名或密码错误!"); } if (!password.equals(user.getPassword())) { throw new IncorrectCredentialsException("用户名或密码错误!"); } if (user.getStatus().equals("0")) { throw new LockedAccountException("账号已被锁定,请联系管理员!"); } SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, password, getName()); return info; } } ================================================ FILE: 13.Spring-Boot-Shiro-Authorization/src/main/java/com/springboot/util/MD5Utils.java ================================================ package com.springboot.util; import org.apache.shiro.crypto.hash.SimpleHash; import org.apache.shiro.util.ByteSource; public class MD5Utils { private static final String SALT = "mrbird"; private static final String ALGORITH_NAME = "md5"; private static final int HASH_ITERATIONS = 2; public static String encrypt(String pswd) { String newPassword = new SimpleHash(ALGORITH_NAME, pswd, ByteSource.Util.bytes(SALT), HASH_ITERATIONS).toHex(); return newPassword; } public static String encrypt(String username, String pswd) { String newPassword = new SimpleHash(ALGORITH_NAME, pswd, ByteSource.Util.bytes(username + SALT), HASH_ITERATIONS).toHex(); return newPassword; } public static void main(String[] args) { System.out.println(MD5Utils.encrypt("tester", "123456")); } } ================================================ FILE: 13.Spring-Boot-Shiro-Authorization/src/main/resources/application.yml ================================================ server: context-path: /web spring: datasource: druid: # 数据库访问配置, 使用druid数据源 type: com.alibaba.druid.pool.DruidDataSource driver-class-name: oracle.jdbc.driver.OracleDriver url: jdbc:oracle:thin:@localhost:1521:ORCL username: test password: 123456 # 连接池配置 initial-size: 5 min-idle: 5 max-active: 20 # 连接等待超时时间 max-wait: 30000 # 配置检测可以关闭的空闲连接间隔时间 time-between-eviction-runs-millis: 60000 # 配置连接在池中的最小生存时间 min-evictable-idle-time-millis: 300000 validation-query: select '1' from dual test-while-idle: true test-on-borrow: false test-on-return: false # 打开PSCache,并且指定每个连接上PSCache的大小 pool-prepared-statements: true max-open-prepared-statements: 20 max-pool-prepared-statement-per-connection-size: 20 # 配置监控统计拦截的filters, 去掉后监控界面sql无法统计, 'wall'用于防火墙 filters: stat # Spring监控AOP切入点,如x.y.z.service.*,配置多个英文逗号分隔 aop-patterns: com.springboot.servie.* # WebStatFilter配置 web-stat-filter: enabled: true # 添加过滤规则 url-pattern: /* # 忽略过滤的格式 exclusions: '*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*' # StatViewServlet配置 stat-view-servlet: enabled: true # 访问路径为/druid时,跳转到StatViewServlet url-pattern: /druid/* # 是否能够重置数据 reset-enable: false # 需要账号密码才能访问控制台 login-username: druid login-password: druid123 # IP白名单 # allow: 127.0.0.1 # IP黑名单(共同存在时,deny优先于allow) # deny: 192.168.1.218 # 配置StatFilter filter: stat: log-slow-sql: true thymeleaf: cache: false mybatis: # type-aliases扫描路径 type-aliases-package: com.springboot.pojo # mapper xml实现扫描路径 mapper-locations: classpath:mapper/*.xml property: order: BEFORE ================================================ FILE: 13.Spring-Boot-Shiro-Authorization/src/main/resources/init.sql ================================================ -- ---------------------------- -- Table structure for T_PERMISSION -- ---------------------------- CREATE TABLE T_PERMISSION ( ID NUMBER(10) NOT NULL , URL VARCHAR2(256 BYTE) NULL , NAME VARCHAR2(64 BYTE) NULL ); COMMENT ON COLUMN T_PERMISSION.URL IS 'url地址'; COMMENT ON COLUMN T_PERMISSION.NAME IS 'url描述'; -- ---------------------------- -- Records of T_PERMISSION -- ---------------------------- INSERT INTO T_PERMISSION VALUES ('1', '/user', 'user:user'); INSERT INTO T_PERMISSION VALUES ('2', '/user/add', 'user:add'); INSERT INTO T_PERMISSION VALUES ('3', '/user/delete', 'user:delete'); -- ---------------------------- -- Table structure for T_ROLE -- ---------------------------- CREATE TABLE T_ROLE ( ID NUMBER NOT NULL , NAME VARCHAR2(32 BYTE) NULL , MEMO VARCHAR2(32 BYTE) NULL ); COMMENT ON COLUMN T_ROLE.NAME IS '角色名称'; COMMENT ON COLUMN T_ROLE.MEMO IS '角色描述'; -- ---------------------------- -- Records of T_ROLE -- ---------------------------- INSERT INTO T_ROLE VALUES ('1', 'admin', '超级管理员'); INSERT INTO T_ROLE VALUES ('2', 'test', '测试账户'); -- ---------------------------- -- Table structure for T_ROLE_PERMISSION -- ---------------------------- CREATE TABLE T_ROLE_PERMISSION ( RID NUMBER(10) NULL , PID NUMBER(10) NULL ); COMMENT ON COLUMN T_ROLE_PERMISSION.RID IS '角色id'; COMMENT ON COLUMN T_ROLE_PERMISSION.PID IS '权限id'; -- ---------------------------- -- Records of T_ROLE_PERMISSION -- ---------------------------- INSERT INTO T_ROLE_PERMISSION VALUES ('1', '2'); INSERT INTO T_ROLE_PERMISSION VALUES ('1', '3'); INSERT INTO T_ROLE_PERMISSION VALUES ('2', '1'); INSERT INTO T_ROLE_PERMISSION VALUES ('1', '1'); -- ---------------------------- -- Table structure for T_USER -- ---------------------------- CREATE TABLE T_USER ( ID NUMBER NOT NULL , USERNAME VARCHAR2(20 BYTE) NOT NULL , PASSWD VARCHAR2(128 BYTE) NOT NULL , CREATE_TIME DATE NULL , STATUS CHAR(1 BYTE) NOT NULL ); COMMENT ON COLUMN T_USER.USERNAME IS '用户名'; COMMENT ON COLUMN T_USER.PASSWD IS '密码'; COMMENT ON COLUMN T_USER.CREATE_TIME IS '创建时间'; COMMENT ON COLUMN T_USER.STATUS IS '是否有效 1:有效 0:锁定'; -- ---------------------------- -- Records of T_USER -- ---------------------------- INSERT INTO T_USER VALUES ('2', 'tester', '243e29429b340192700677d48c09d992', TO_DATE('2017-12-11 17:20:21', 'YYYY-MM-DD HH24:MI:SS'), '1'); INSERT INTO T_USER VALUES ('1', 'mrbird', '42ee25d1e43e9f57119a00d0a39e5250', TO_DATE('2017-12-11 10:52:48', 'YYYY-MM-DD HH24:MI:SS'), '1'); -- ---------------------------- -- Table structure for T_USER_ROLE -- ---------------------------- CREATE TABLE T_USER_ROLE ( USER_ID NUMBER(10) NULL , RID NUMBER(10) NULL ); COMMENT ON COLUMN T_USER_ROLE.USER_ID IS '用户id'; COMMENT ON COLUMN T_USER_ROLE.RID IS '角色id'; -- ---------------------------- -- Records of T_USER_ROLE -- ---------------------------- INSERT INTO T_USER_ROLE VALUES ('1', '1'); INSERT INTO T_USER_ROLE VALUES ('2', '2'); ================================================ FILE: 13.Spring-Boot-Shiro-Authorization/src/main/resources/mapper/UserMapper.xml ================================================ ================================================ FILE: 13.Spring-Boot-Shiro-Authorization/src/main/resources/mapper/UserPermissionMapper.xml ================================================ ================================================ FILE: 13.Spring-Boot-Shiro-Authorization/src/main/resources/mapper/UserRoleMapper.xml ================================================ ================================================ FILE: 13.Spring-Boot-Shiro-Authorization/src/main/resources/static/css/login.css ================================================ .login-page { width: 360px; padding: 8% 0 0; margin: auto; } .form { position: relative; z-index: 1; background: #ffffff; max-width: 360px; margin: 0 auto 100px; padding: 45px; text-align: center; box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.2), 0 5px 5px 0 rgba(0, 0, 0, 0.24); } .form input { outline: 0; background: #f2f2f2; width: 100%; border: 0; margin: 0 0 15px; padding: 15px; box-sizing: border-box; font-size: 14px; } .form button { text-transform: uppercase; outline: 0; background: #4caf50; width: 100%; border: 0; padding: 15px; color: #ffffff; font-size: 14px; -webkit-transition: all 0.3 ease; transition: all 0.3 ease; cursor: pointer; } .form button:hover, .form button:active, .form button:focus { background: #43a047; } .form .message { margin: 15px 0 0; color: #b3b3b3; font-size: 12px; } .form .message a { color: #4caf50; text-decoration: none; } .form .register-form { display: none; } .form p { text-align: left; margin: 0; font-size: 13px; } .form p input { width: auto; margin-right: 10px; } .container { position: relative; z-index: 1; max-width: 300px; margin: 0 auto; } .container:before, .container:after { content: ""; display: block; clear: both; } .container .info { margin: 50px auto; text-align: center; } .container .info h1 { margin: 0 0 15px; padding: 0; font-size: 36px; font-weight: 300; color: #1a1a1a; } .container .info span { color: #4d4d4d; font-size: 12px; } .container .info span a { color: #000000; text-decoration: none; } .container .info span .fa { color: #ef3b3a; } body { background: #76b852; /* fallback for old browsers */ background: -webkit-linear-gradient(right, #76b852, #8dc26f); background: -moz-linear-gradient(right, #76b852, #8dc26f); background: -o-linear-gradient(right, #76b852, #8dc26f); background: linear-gradient(to left, #76b852, #8dc26f); font-family: Lato,"PingFang SC","Microsoft YaHei",sans-serif; } ================================================ FILE: 13.Spring-Boot-Shiro-Authorization/src/main/resources/templates/403.html ================================================ 暂无权限

您没有权限访问该资源!!

返回 ================================================ FILE: 13.Spring-Boot-Shiro-Authorization/src/main/resources/templates/index.html ================================================ 首页

你好![[${user.userName}]]

权限测试链接

注销 ================================================ FILE: 13.Spring-Boot-Shiro-Authorization/src/main/resources/templates/login.html ================================================ 登录 ================================================ FILE: 13.Spring-Boot-Shiro-Authorization/src/main/resources/templates/user.html ================================================ [[${value}]]

[[${value}]]

返回 ================================================ FILE: 14.Spring-Boot-Shiro-Redis/pom.xml ================================================ 4.0.0 com.springboot Spring-Boot-Shiro-Redis 0.0.1-SNAPSHOT jar demo Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.9.RELEASE UTF-8 UTF-8 1.7 3.0.2.RELEASE 2.0.1 org.springframework.boot spring-boot-starter-web org.mybatis.spring.boot mybatis-spring-boot-starter 1.3.1 org.springframework.boot spring-boot-starter-thymeleaf org.apache.shiro shiro-spring 1.4.0 org.crazycake shiro-redis 2.4.2.1-RELEASE com.oracle ojdbc6 6.0 com.alibaba druid-spring-boot-starter 1.1.6 org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 14.Spring-Boot-Shiro-Redis/src/main/java/com/springboot/Application.java ================================================ package com.springboot; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class,args); } } ================================================ FILE: 14.Spring-Boot-Shiro-Redis/src/main/java/com/springboot/config/ShiroConfig.java ================================================ package com.springboot.config; import java.util.LinkedHashMap; import org.apache.shiro.codec.Base64; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.spring.LifecycleBeanPostProcessor; import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.CookieRememberMeManager; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.apache.shiro.web.servlet.SimpleCookie; import org.crazycake.shiro.RedisCacheManager; import org.crazycake.shiro.RedisManager; import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.DependsOn; import com.springboot.shiro.ShiroRealm; @Configuration public class ShiroConfig { @Bean public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager); shiroFilterFactoryBean.setLoginUrl("/login"); shiroFilterFactoryBean.setSuccessUrl("/index"); shiroFilterFactoryBean.setUnauthorizedUrl("/403"); LinkedHashMap filterChainDefinitionMap = new LinkedHashMap<>(); filterChainDefinitionMap.put("/css/**", "anon"); filterChainDefinitionMap.put("/js/**", "anon"); filterChainDefinitionMap.put("/fonts/**", "anon"); filterChainDefinitionMap.put("/img/**", "anon"); filterChainDefinitionMap.put("/druid/**", "anon"); filterChainDefinitionMap.put("/logout", "logout"); filterChainDefinitionMap.put("/", "anon"); filterChainDefinitionMap.put("/**", "user"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } @Bean public SecurityManager securityManager(){ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(shiroRealm()); securityManager.setRememberMeManager(rememberMeManager()); securityManager.setCacheManager(cacheManager()); return securityManager; } @Bean(name = "lifecycleBeanPostProcessor") public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { return new LifecycleBeanPostProcessor(); } @Bean public ShiroRealm shiroRealm(){ ShiroRealm shiroRealm = new ShiroRealm(); return shiroRealm; } public SimpleCookie rememberMeCookie() { SimpleCookie cookie = new SimpleCookie("rememberMe"); cookie.setMaxAge(86400); return cookie; } public CookieRememberMeManager rememberMeManager() { CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager(); cookieRememberMeManager.setCookie(rememberMeCookie()); cookieRememberMeManager.setCipherKey(Base64.decode("4AvVhmFLUs0KTA3Kprsdag==")); return cookieRememberMeManager; } @Bean @DependsOn({"lifecycleBeanPostProcessor"}) public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() { DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator(); advisorAutoProxyCreator.setProxyTargetClass(true); return advisorAutoProxyCreator; } @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) { AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); return authorizationAttributeSourceAdvisor; } public RedisManager redisManager() { RedisManager redisManager = new RedisManager(); return redisManager; } public RedisCacheManager cacheManager() { RedisCacheManager redisCacheManager = new RedisCacheManager(); redisCacheManager.setRedisManager(redisManager()); return redisCacheManager; } } ================================================ FILE: 14.Spring-Boot-Shiro-Redis/src/main/java/com/springboot/controller/LoginController.java ================================================ package com.springboot.controller; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.LockedAccountException; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.subject.Subject; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import com.springboot.pojo.ResponseBo; import com.springboot.pojo.User; import com.springboot.util.MD5Utils; @Controller public class LoginController { @GetMapping("/login") public String login() { return "login"; } @PostMapping("/login") @ResponseBody public ResponseBo login(String username, String password, Boolean rememberMe) { password = MD5Utils.encrypt(username, password); UsernamePasswordToken token = new UsernamePasswordToken(username, password, rememberMe); Subject subject = SecurityUtils.getSubject(); try { subject.login(token); return ResponseBo.ok(); } catch (UnknownAccountException e) { return ResponseBo.error(e.getMessage()); } catch (IncorrectCredentialsException e) { return ResponseBo.error(e.getMessage()); } catch (LockedAccountException e) { return ResponseBo.error(e.getMessage()); } catch (AuthenticationException e) { return ResponseBo.error("认证失败!"); } } @RequestMapping("/") public String redirectIndex() { return "redirect:/index"; } @GetMapping("/403") public String forbid() { return "403"; } @RequestMapping("/index") public String index(Model model) { User user = (User) SecurityUtils.getSubject().getPrincipal(); model.addAttribute("user", user); return "index"; } } ================================================ FILE: 14.Spring-Boot-Shiro-Redis/src/main/java/com/springboot/controller/UserController.java ================================================ package com.springboot.controller; import org.apache.shiro.authz.annotation.RequiresPermissions; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; @Controller @RequestMapping("/user") public class UserController { @RequiresPermissions("user:user") @RequestMapping("list") public String userList(Model model) { model.addAttribute("value", "获取用户信息"); return "user"; } @RequiresPermissions("user:add") @RequestMapping("add") public String userAdd(Model model) { model.addAttribute("value", "新增用户"); return "user"; } @RequiresPermissions("user:delete") @RequestMapping("delete") public String userDelete(Model model) { model.addAttribute("value", "删除用户"); return "user"; } } ================================================ FILE: 14.Spring-Boot-Shiro-Redis/src/main/java/com/springboot/dao/UserMapper.java ================================================ package com.springboot.dao; import org.apache.ibatis.annotations.Mapper; import com.springboot.pojo.User; @Mapper public interface UserMapper { User findByUserName(String userName); } ================================================ FILE: 14.Spring-Boot-Shiro-Redis/src/main/java/com/springboot/dao/UserPermissionMapper.java ================================================ package com.springboot.dao; import java.util.List; import org.apache.ibatis.annotations.Mapper; import com.springboot.pojo.Permission; @Mapper public interface UserPermissionMapper { List findByUserName(String userName); } ================================================ FILE: 14.Spring-Boot-Shiro-Redis/src/main/java/com/springboot/dao/UserRoleMapper.java ================================================ package com.springboot.dao; import java.util.List; import org.apache.ibatis.annotations.Mapper; import com.springboot.pojo.Role; @Mapper public interface UserRoleMapper { List findByUserName(String userName); } ================================================ FILE: 14.Spring-Boot-Shiro-Redis/src/main/java/com/springboot/handler/GlobalExceptionHandler.java ================================================ package com.springboot.handler; import org.apache.shiro.authz.AuthorizationException; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; @ControllerAdvice @Order(value = Ordered.HIGHEST_PRECEDENCE) public class GlobalExceptionHandler { @ExceptionHandler(value = AuthorizationException.class) public String handleAuthorizationException() { return "403"; } } ================================================ FILE: 14.Spring-Boot-Shiro-Redis/src/main/java/com/springboot/pojo/Permission.java ================================================ package com.springboot.pojo; import java.io.Serializable; public class Permission implements Serializable{ private static final long serialVersionUID = 7160557680614732403L; private Integer id; private String url; private String name; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getName() { return name; } public void setName(String name) { this.name = name; } } ================================================ FILE: 14.Spring-Boot-Shiro-Redis/src/main/java/com/springboot/pojo/ResponseBo.java ================================================ package com.springboot.pojo; import java.util.HashMap; import java.util.Map; public class ResponseBo extends HashMap{ private static final long serialVersionUID = 1L; public ResponseBo() { put("code", 0); put("msg", "操作成功"); } public static ResponseBo error() { return error(1, "操作失败"); } public static ResponseBo error(String msg) { return error(500, msg); } public static ResponseBo error(int code, String msg) { ResponseBo ResponseBo = new ResponseBo(); ResponseBo.put("code", code); ResponseBo.put("msg", msg); return ResponseBo; } public static ResponseBo ok(String msg) { ResponseBo ResponseBo = new ResponseBo(); ResponseBo.put("msg", msg); return ResponseBo; } public static ResponseBo ok(Map map) { ResponseBo ResponseBo = new ResponseBo(); ResponseBo.putAll(map); return ResponseBo; } public static ResponseBo ok() { return new ResponseBo(); } @Override public ResponseBo put(String key, Object value) { super.put(key, value); return this; } } ================================================ FILE: 14.Spring-Boot-Shiro-Redis/src/main/java/com/springboot/pojo/Role.java ================================================ package com.springboot.pojo; import java.io.Serializable; public class Role implements Serializable{ private static final long serialVersionUID = -227437593919820521L; private Integer id; private String name; private String memo; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getMemo() { return memo; } public void setMemo(String memo) { this.memo = memo; } } ================================================ FILE: 14.Spring-Boot-Shiro-Redis/src/main/java/com/springboot/pojo/User.java ================================================ package com.springboot.pojo; import java.io.Serializable; import java.util.Date; public class User implements Serializable{ private static final long serialVersionUID = -5440372534300871944L; private Integer id; private String userName; private String password; private Date createTime; private String status; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Date getCreateTime() { return createTime; } public void setCreateTime(Date createTime) { this.createTime = createTime; } public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } } ================================================ FILE: 14.Spring-Boot-Shiro-Redis/src/main/java/com/springboot/shiro/ShiroRealm.java ================================================ package com.springboot.shiro; import java.util.HashSet; import java.util.List; import java.util.Set; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.LockedAccountException; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.springframework.beans.factory.annotation.Autowired; import com.springboot.dao.UserMapper; import com.springboot.dao.UserPermissionMapper; import com.springboot.dao.UserRoleMapper; import com.springboot.pojo.Permission; import com.springboot.pojo.Role; import com.springboot.pojo.User; public class ShiroRealm extends AuthorizingRealm { @Autowired private UserMapper userMapper; @Autowired private UserRoleMapper userRoleMapper; @Autowired private UserPermissionMapper userPermissionMapper; /** * 获取用户角色和权限 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) { User user = (User) SecurityUtils.getSubject().getPrincipal(); String userName = user.getUserName(); System.out.println("用户" + userName + "获取权限-----ShiroRealm.doGetAuthorizationInfo"); SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(); // 获取用户角色集 List roleList = userRoleMapper.findByUserName(userName); Set roleSet = new HashSet(); for (Role r : roleList) { roleSet.add(r.getName()); } simpleAuthorizationInfo.setRoles(roleSet); // 获取用户权限集 List permissionList = userPermissionMapper.findByUserName(userName); Set permissionSet = new HashSet(); for (Permission p : permissionList) { permissionSet.add(p.getName()); } simpleAuthorizationInfo.setStringPermissions(permissionSet); return simpleAuthorizationInfo; } /** * 登录认证 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { String userName = (String) token.getPrincipal(); String password = new String((char[]) token.getCredentials()); System.out.println("用户" + userName + "认证-----ShiroRealm.doGetAuthenticationInfo"); User user = userMapper.findByUserName(userName); if (user == null) { throw new UnknownAccountException("用户名或密码错误!"); } if (!password.equals(user.getPassword())) { throw new IncorrectCredentialsException("用户名或密码错误!"); } if (user.getStatus().equals("0")) { throw new LockedAccountException("账号已被锁定,请联系管理员!"); } SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, password, getName()); return info; } } ================================================ FILE: 14.Spring-Boot-Shiro-Redis/src/main/java/com/springboot/util/MD5Utils.java ================================================ package com.springboot.util; import org.apache.shiro.crypto.hash.SimpleHash; import org.apache.shiro.util.ByteSource; public class MD5Utils { private static final String SALT = "mrbird"; private static final String ALGORITH_NAME = "md5"; private static final int HASH_ITERATIONS = 2; public static String encrypt(String pswd) { String newPassword = new SimpleHash(ALGORITH_NAME, pswd, ByteSource.Util.bytes(SALT), HASH_ITERATIONS).toHex(); return newPassword; } public static String encrypt(String username, String pswd) { String newPassword = new SimpleHash(ALGORITH_NAME, pswd, ByteSource.Util.bytes(username + SALT), HASH_ITERATIONS).toHex(); return newPassword; } public static void main(String[] args) { System.out.println(MD5Utils.encrypt("tester", "123456")); } } ================================================ FILE: 14.Spring-Boot-Shiro-Redis/src/main/resources/application.yml ================================================ server: context-path: /web spring: datasource: druid: # 数据库访问配置, 使用druid数据源 type: com.alibaba.druid.pool.DruidDataSource driver-class-name: oracle.jdbc.driver.OracleDriver url: jdbc:oracle:thin:@localhost:1521:ORCL username: test password: 123456 # 连接池配置 initial-size: 5 min-idle: 5 max-active: 20 # 连接等待超时时间 max-wait: 30000 # 配置检测可以关闭的空闲连接间隔时间 time-between-eviction-runs-millis: 60000 # 配置连接在池中的最小生存时间 min-evictable-idle-time-millis: 300000 validation-query: select '1' from dual test-while-idle: true test-on-borrow: false test-on-return: false # 打开PSCache,并且指定每个连接上PSCache的大小 pool-prepared-statements: true max-open-prepared-statements: 20 max-pool-prepared-statement-per-connection-size: 20 # 配置监控统计拦截的filters, 去掉后监控界面sql无法统计, 'wall'用于防火墙 filters: stat # Spring监控AOP切入点,如x.y.z.service.*,配置多个英文逗号分隔 aop-patterns: com.springboot.servie.* # WebStatFilter配置 web-stat-filter: enabled: true # 添加过滤规则 url-pattern: /* # 忽略过滤的格式 exclusions: '*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*' # StatViewServlet配置 stat-view-servlet: enabled: true # 访问路径为/druid时,跳转到StatViewServlet url-pattern: /druid/* # 是否能够重置数据 reset-enable: false # 需要账号密码才能访问控制台 login-username: druid login-password: druid123 # IP白名单 # allow: 127.0.0.1 # IP黑名单(共同存在时,deny优先于allow) # deny: 192.168.1.218 # 配置StatFilter filter: stat: log-slow-sql: true thymeleaf: cache: false redis: host: localhost port: 6379 pool: max-active: 8 max-wait: -1 max-idle: 8 min-idle: 0 timeout: 0 mybatis: # type-aliases扫描路径 type-aliases-package: com.springboot.pojo # mapper xml实现扫描路径 mapper-locations: classpath:mapper/*.xml property: order: BEFORE ================================================ FILE: 14.Spring-Boot-Shiro-Redis/src/main/resources/init.sql ================================================ -- ---------------------------- -- Table structure for T_PERMISSION -- ---------------------------- CREATE TABLE T_PERMISSION ( ID NUMBER(10) NOT NULL , URL VARCHAR2(256 BYTE) NULL , NAME VARCHAR2(64 BYTE) NULL ); COMMENT ON COLUMN T_PERMISSION.URL IS 'url地址'; COMMENT ON COLUMN T_PERMISSION.NAME IS 'url描述'; -- ---------------------------- -- Records of T_PERMISSION -- ---------------------------- INSERT INTO T_PERMISSION VALUES ('1', '/user', 'user:user'); INSERT INTO T_PERMISSION VALUES ('2', '/user/add', 'user:add'); INSERT INTO T_PERMISSION VALUES ('3', '/user/delete', 'user:delete'); -- ---------------------------- -- Table structure for T_ROLE -- ---------------------------- CREATE TABLE T_ROLE ( ID NUMBER NOT NULL , NAME VARCHAR2(32 BYTE) NULL , MEMO VARCHAR2(32 BYTE) NULL ); COMMENT ON COLUMN T_ROLE.NAME IS '角色名称'; COMMENT ON COLUMN T_ROLE.MEMO IS '角色描述'; -- ---------------------------- -- Records of T_ROLE -- ---------------------------- INSERT INTO T_ROLE VALUES ('1', 'admin', '超级管理员'); INSERT INTO T_ROLE VALUES ('2', 'test', '测试账户'); -- ---------------------------- -- Table structure for T_ROLE_PERMISSION -- ---------------------------- CREATE TABLE T_ROLE_PERMISSION ( RID NUMBER(10) NULL , PID NUMBER(10) NULL ); COMMENT ON COLUMN T_ROLE_PERMISSION.RID IS '角色id'; COMMENT ON COLUMN T_ROLE_PERMISSION.PID IS '权限id'; -- ---------------------------- -- Records of T_ROLE_PERMISSION -- ---------------------------- INSERT INTO T_ROLE_PERMISSION VALUES ('1', '2'); INSERT INTO T_ROLE_PERMISSION VALUES ('1', '3'); INSERT INTO T_ROLE_PERMISSION VALUES ('2', '1'); INSERT INTO T_ROLE_PERMISSION VALUES ('1', '1'); -- ---------------------------- -- Table structure for T_USER -- ---------------------------- CREATE TABLE T_USER ( ID NUMBER NOT NULL , USERNAME VARCHAR2(20 BYTE) NOT NULL , PASSWD VARCHAR2(128 BYTE) NOT NULL , CREATE_TIME DATE NULL , STATUS CHAR(1 BYTE) NOT NULL ); COMMENT ON COLUMN T_USER.USERNAME IS '用户名'; COMMENT ON COLUMN T_USER.PASSWD IS '密码'; COMMENT ON COLUMN T_USER.CREATE_TIME IS '创建时间'; COMMENT ON COLUMN T_USER.STATUS IS '是否有效 1:有效 0:锁定'; -- ---------------------------- -- Records of T_USER -- ---------------------------- INSERT INTO T_USER VALUES ('2', 'tester', '243e29429b340192700677d48c09d992', TO_DATE('2017-12-11 17:20:21', 'YYYY-MM-DD HH24:MI:SS'), '1'); INSERT INTO T_USER VALUES ('1', 'mrbird', '42ee25d1e43e9f57119a00d0a39e5250', TO_DATE('2017-12-11 10:52:48', 'YYYY-MM-DD HH24:MI:SS'), '1'); -- ---------------------------- -- Table structure for T_USER_ROLE -- ---------------------------- CREATE TABLE T_USER_ROLE ( USER_ID NUMBER(10) NULL , RID NUMBER(10) NULL ); COMMENT ON COLUMN T_USER_ROLE.USER_ID IS '用户id'; COMMENT ON COLUMN T_USER_ROLE.RID IS '角色id'; -- ---------------------------- -- Records of T_USER_ROLE -- ---------------------------- INSERT INTO T_USER_ROLE VALUES ('1', '1'); INSERT INTO T_USER_ROLE VALUES ('2', '2'); ================================================ FILE: 14.Spring-Boot-Shiro-Redis/src/main/resources/mapper/UserMapper.xml ================================================ ================================================ FILE: 14.Spring-Boot-Shiro-Redis/src/main/resources/mapper/UserPermissionMapper.xml ================================================ ================================================ FILE: 14.Spring-Boot-Shiro-Redis/src/main/resources/mapper/UserRoleMapper.xml ================================================ ================================================ FILE: 14.Spring-Boot-Shiro-Redis/src/main/resources/static/css/login.css ================================================ .login-page { width: 360px; padding: 8% 0 0; margin: auto; } .form { position: relative; z-index: 1; background: #ffffff; max-width: 360px; margin: 0 auto 100px; padding: 45px; text-align: center; box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.2), 0 5px 5px 0 rgba(0, 0, 0, 0.24); } .form input { outline: 0; background: #f2f2f2; width: 100%; border: 0; margin: 0 0 15px; padding: 15px; box-sizing: border-box; font-size: 14px; } .form button { text-transform: uppercase; outline: 0; background: #4caf50; width: 100%; border: 0; padding: 15px; color: #ffffff; font-size: 14px; -webkit-transition: all 0.3 ease; transition: all 0.3 ease; cursor: pointer; } .form button:hover, .form button:active, .form button:focus { background: #43a047; } .form .message { margin: 15px 0 0; color: #b3b3b3; font-size: 12px; } .form .message a { color: #4caf50; text-decoration: none; } .form .register-form { display: none; } .form p { text-align: left; margin: 0; font-size: 13px; } .form p input { width: auto; margin-right: 10px; } .container { position: relative; z-index: 1; max-width: 300px; margin: 0 auto; } .container:before, .container:after { content: ""; display: block; clear: both; } .container .info { margin: 50px auto; text-align: center; } .container .info h1 { margin: 0 0 15px; padding: 0; font-size: 36px; font-weight: 300; color: #1a1a1a; } .container .info span { color: #4d4d4d; font-size: 12px; } .container .info span a { color: #000000; text-decoration: none; } .container .info span .fa { color: #ef3b3a; } body { background: #76b852; /* fallback for old browsers */ background: -webkit-linear-gradient(right, #76b852, #8dc26f); background: -moz-linear-gradient(right, #76b852, #8dc26f); background: -o-linear-gradient(right, #76b852, #8dc26f); background: linear-gradient(to left, #76b852, #8dc26f); font-family: Lato,"PingFang SC","Microsoft YaHei",sans-serif; } ================================================ FILE: 14.Spring-Boot-Shiro-Redis/src/main/resources/templates/403.html ================================================ 暂无权限

您没有权限访问该资源!!

返回 ================================================ FILE: 14.Spring-Boot-Shiro-Redis/src/main/resources/templates/index.html ================================================ 首页

你好![[${user.userName}]]

权限测试链接

注销 ================================================ FILE: 14.Spring-Boot-Shiro-Redis/src/main/resources/templates/login.html ================================================ 登录 ================================================ FILE: 14.Spring-Boot-Shiro-Redis/src/main/resources/templates/user.html ================================================ [[${value}]]

[[${value}]]

返回 ================================================ FILE: 15.Spring-Boot-Shiro-Ehcache/pom.xml ================================================ 4.0.0 com.springboot Spring-Boot-Shiro-Ehcache 0.0.1-SNAPSHOT jar demo Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.9.RELEASE UTF-8 UTF-8 1.7 3.0.2.RELEASE 2.0.1 org.springframework.boot spring-boot-starter-web org.mybatis.spring.boot mybatis-spring-boot-starter 1.3.1 org.springframework.boot spring-boot-starter-thymeleaf org.apache.shiro shiro-spring 1.4.0 org.apache.shiro shiro-ehcache 1.3.2 org.springframework.boot spring-boot-starter-cache net.sf.ehcache ehcache com.oracle ojdbc6 6.0 com.alibaba druid-spring-boot-starter 1.1.6 org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 15.Spring-Boot-Shiro-Ehcache/src/main/java/com/springboot/Application.java ================================================ package com.springboot; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class,args); } } ================================================ FILE: 15.Spring-Boot-Shiro-Ehcache/src/main/java/com/springboot/config/ShiroConfig.java ================================================ package com.springboot.config; import java.util.LinkedHashMap; import org.apache.shiro.cache.ehcache.EhCacheManager; import org.apache.shiro.codec.Base64; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.spring.LifecycleBeanPostProcessor; import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.CookieRememberMeManager; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.apache.shiro.web.servlet.SimpleCookie; import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.DependsOn; import com.springboot.shiro.ShiroRealm; @Configuration public class ShiroConfig { @Bean public EhCacheManager getEhCacheManager() { EhCacheManager em = new EhCacheManager(); em.setCacheManagerConfigFile("classpath:config/shiro-ehcache.xml"); return em; } @Bean public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager); shiroFilterFactoryBean.setLoginUrl("/login"); shiroFilterFactoryBean.setSuccessUrl("/index"); shiroFilterFactoryBean.setUnauthorizedUrl("/403"); LinkedHashMap filterChainDefinitionMap = new LinkedHashMap<>(); filterChainDefinitionMap.put("/css/**", "anon"); filterChainDefinitionMap.put("/js/**", "anon"); filterChainDefinitionMap.put("/fonts/**", "anon"); filterChainDefinitionMap.put("/img/**", "anon"); filterChainDefinitionMap.put("/druid/**", "anon"); filterChainDefinitionMap.put("/logout", "logout"); filterChainDefinitionMap.put("/", "anon"); filterChainDefinitionMap.put("/**", "user"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } @Bean public SecurityManager securityManager(){ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(shiroRealm()); securityManager.setRememberMeManager(rememberMeManager()); securityManager.setCacheManager(getEhCacheManager()); return securityManager; } @Bean(name = "lifecycleBeanPostProcessor") public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { return new LifecycleBeanPostProcessor(); } @Bean public ShiroRealm shiroRealm(){ ShiroRealm shiroRealm = new ShiroRealm(); return shiroRealm; } public SimpleCookie rememberMeCookie() { SimpleCookie cookie = new SimpleCookie("rememberMe"); cookie.setMaxAge(86400); return cookie; } public CookieRememberMeManager rememberMeManager() { CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager(); cookieRememberMeManager.setCookie(rememberMeCookie()); cookieRememberMeManager.setCipherKey(Base64.decode("4AvVhmFLUs0KTA3Kprsdag==")); return cookieRememberMeManager; } @Bean @DependsOn({"lifecycleBeanPostProcessor"}) public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() { DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator(); advisorAutoProxyCreator.setProxyTargetClass(true); return advisorAutoProxyCreator; } @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) { AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); return authorizationAttributeSourceAdvisor; } } ================================================ FILE: 15.Spring-Boot-Shiro-Ehcache/src/main/java/com/springboot/controller/LoginController.java ================================================ package com.springboot.controller; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.LockedAccountException; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.subject.Subject; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import com.springboot.pojo.ResponseBo; import com.springboot.pojo.User; import com.springboot.util.MD5Utils; @Controller public class LoginController { @GetMapping("/login") public String login() { return "login"; } @PostMapping("/login") @ResponseBody public ResponseBo login(String username, String password, Boolean rememberMe) { password = MD5Utils.encrypt(username, password); UsernamePasswordToken token = new UsernamePasswordToken(username, password, rememberMe); Subject subject = SecurityUtils.getSubject(); try { subject.login(token); return ResponseBo.ok(); } catch (UnknownAccountException e) { return ResponseBo.error(e.getMessage()); } catch (IncorrectCredentialsException e) { return ResponseBo.error(e.getMessage()); } catch (LockedAccountException e) { return ResponseBo.error(e.getMessage()); } catch (AuthenticationException e) { return ResponseBo.error("认证失败!"); } } @RequestMapping("/") public String redirectIndex() { return "redirect:/index"; } @GetMapping("/403") public String forbid() { return "403"; } @RequestMapping("/index") public String index(Model model) { User user = (User) SecurityUtils.getSubject().getPrincipal(); model.addAttribute("user", user); return "index"; } } ================================================ FILE: 15.Spring-Boot-Shiro-Ehcache/src/main/java/com/springboot/controller/UserController.java ================================================ package com.springboot.controller; import org.apache.shiro.authz.annotation.RequiresPermissions; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; @Controller @RequestMapping("/user") public class UserController { @RequiresPermissions("user:user") @RequestMapping("list") public String userList(Model model) { model.addAttribute("value", "获取用户信息"); return "user"; } @RequiresPermissions("user:add") @RequestMapping("add") public String userAdd(Model model) { model.addAttribute("value", "新增用户"); return "user"; } @RequiresPermissions("user:delete") @RequestMapping("delete") public String userDelete(Model model) { model.addAttribute("value", "删除用户"); return "user"; } } ================================================ FILE: 15.Spring-Boot-Shiro-Ehcache/src/main/java/com/springboot/dao/UserMapper.java ================================================ package com.springboot.dao; import org.apache.ibatis.annotations.Mapper; import com.springboot.pojo.User; @Mapper public interface UserMapper { User findByUserName(String userName); } ================================================ FILE: 15.Spring-Boot-Shiro-Ehcache/src/main/java/com/springboot/dao/UserPermissionMapper.java ================================================ package com.springboot.dao; import java.util.List; import org.apache.ibatis.annotations.Mapper; import com.springboot.pojo.Permission; @Mapper public interface UserPermissionMapper { List findByUserName(String userName); } ================================================ FILE: 15.Spring-Boot-Shiro-Ehcache/src/main/java/com/springboot/dao/UserRoleMapper.java ================================================ package com.springboot.dao; import java.util.List; import org.apache.ibatis.annotations.Mapper; import com.springboot.pojo.Role; @Mapper public interface UserRoleMapper { List findByUserName(String userName); } ================================================ FILE: 15.Spring-Boot-Shiro-Ehcache/src/main/java/com/springboot/handler/GlobalExceptionHandler.java ================================================ package com.springboot.handler; import org.apache.shiro.authz.AuthorizationException; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; @ControllerAdvice @Order(value = Ordered.HIGHEST_PRECEDENCE) public class GlobalExceptionHandler { @ExceptionHandler(value = AuthorizationException.class) public String handleAuthorizationException() { return "403"; } } ================================================ FILE: 15.Spring-Boot-Shiro-Ehcache/src/main/java/com/springboot/pojo/Permission.java ================================================ package com.springboot.pojo; import java.io.Serializable; public class Permission implements Serializable{ private static final long serialVersionUID = 7160557680614732403L; private Integer id; private String url; private String name; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getName() { return name; } public void setName(String name) { this.name = name; } } ================================================ FILE: 15.Spring-Boot-Shiro-Ehcache/src/main/java/com/springboot/pojo/ResponseBo.java ================================================ package com.springboot.pojo; import java.util.HashMap; import java.util.Map; public class ResponseBo extends HashMap{ private static final long serialVersionUID = 1L; public ResponseBo() { put("code", 0); put("msg", "操作成功"); } public static ResponseBo error() { return error(1, "操作失败"); } public static ResponseBo error(String msg) { return error(500, msg); } public static ResponseBo error(int code, String msg) { ResponseBo ResponseBo = new ResponseBo(); ResponseBo.put("code", code); ResponseBo.put("msg", msg); return ResponseBo; } public static ResponseBo ok(String msg) { ResponseBo ResponseBo = new ResponseBo(); ResponseBo.put("msg", msg); return ResponseBo; } public static ResponseBo ok(Map map) { ResponseBo ResponseBo = new ResponseBo(); ResponseBo.putAll(map); return ResponseBo; } public static ResponseBo ok() { return new ResponseBo(); } @Override public ResponseBo put(String key, Object value) { super.put(key, value); return this; } } ================================================ FILE: 15.Spring-Boot-Shiro-Ehcache/src/main/java/com/springboot/pojo/Role.java ================================================ package com.springboot.pojo; import java.io.Serializable; public class Role implements Serializable{ private static final long serialVersionUID = -227437593919820521L; private Integer id; private String name; private String memo; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getMemo() { return memo; } public void setMemo(String memo) { this.memo = memo; } } ================================================ FILE: 15.Spring-Boot-Shiro-Ehcache/src/main/java/com/springboot/pojo/User.java ================================================ package com.springboot.pojo; import java.io.Serializable; import java.util.Date; public class User implements Serializable{ private static final long serialVersionUID = -5440372534300871944L; private Integer id; private String userName; private String password; private Date createTime; private String status; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Date getCreateTime() { return createTime; } public void setCreateTime(Date createTime) { this.createTime = createTime; } public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } } ================================================ FILE: 15.Spring-Boot-Shiro-Ehcache/src/main/java/com/springboot/shiro/ShiroRealm.java ================================================ package com.springboot.shiro; import java.util.HashSet; import java.util.List; import java.util.Set; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.LockedAccountException; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.springframework.beans.factory.annotation.Autowired; import com.springboot.dao.UserMapper; import com.springboot.dao.UserPermissionMapper; import com.springboot.dao.UserRoleMapper; import com.springboot.pojo.Permission; import com.springboot.pojo.Role; import com.springboot.pojo.User; public class ShiroRealm extends AuthorizingRealm { @Autowired private UserMapper userMapper; @Autowired private UserRoleMapper userRoleMapper; @Autowired private UserPermissionMapper userPermissionMapper; /** * 获取用户角色和权限 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) { User user = (User) SecurityUtils.getSubject().getPrincipal(); String userName = user.getUserName(); System.out.println("用户" + userName + "获取权限-----ShiroRealm.doGetAuthorizationInfo"); SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(); // 获取用户角色集 List roleList = userRoleMapper.findByUserName(userName); Set roleSet = new HashSet(); for (Role r : roleList) { roleSet.add(r.getName()); } simpleAuthorizationInfo.setRoles(roleSet); // 获取用户权限集 List permissionList = userPermissionMapper.findByUserName(userName); Set permissionSet = new HashSet(); for (Permission p : permissionList) { permissionSet.add(p.getName()); } simpleAuthorizationInfo.setStringPermissions(permissionSet); return simpleAuthorizationInfo; } /** * 登录认证 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { String userName = (String) token.getPrincipal(); String password = new String((char[]) token.getCredentials()); System.out.println("用户" + userName + "认证-----ShiroRealm.doGetAuthenticationInfo"); User user = userMapper.findByUserName(userName); if (user == null) { throw new UnknownAccountException("用户名或密码错误!"); } if (!password.equals(user.getPassword())) { throw new IncorrectCredentialsException("用户名或密码错误!"); } if (user.getStatus().equals("0")) { throw new LockedAccountException("账号已被锁定,请联系管理员!"); } SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, password, getName()); return info; } } ================================================ FILE: 15.Spring-Boot-Shiro-Ehcache/src/main/java/com/springboot/util/MD5Utils.java ================================================ package com.springboot.util; import org.apache.shiro.crypto.hash.SimpleHash; import org.apache.shiro.util.ByteSource; public class MD5Utils { private static final String SALT = "mrbird"; private static final String ALGORITH_NAME = "md5"; private static final int HASH_ITERATIONS = 2; public static String encrypt(String pswd) { String newPassword = new SimpleHash(ALGORITH_NAME, pswd, ByteSource.Util.bytes(SALT), HASH_ITERATIONS).toHex(); return newPassword; } public static String encrypt(String username, String pswd) { String newPassword = new SimpleHash(ALGORITH_NAME, pswd, ByteSource.Util.bytes(username + SALT), HASH_ITERATIONS).toHex(); return newPassword; } public static void main(String[] args) { System.out.println(MD5Utils.encrypt("tester", "123456")); } } ================================================ FILE: 15.Spring-Boot-Shiro-Ehcache/src/main/resources/application.yml ================================================ server: context-path: /web spring: datasource: druid: # 数据库访问配置, 使用druid数据源 type: com.alibaba.druid.pool.DruidDataSource driver-class-name: oracle.jdbc.driver.OracleDriver url: jdbc:oracle:thin:@localhost:1521:ORCL username: test password: 123456 # 连接池配置 initial-size: 5 min-idle: 5 max-active: 20 # 连接等待超时时间 max-wait: 30000 # 配置检测可以关闭的空闲连接间隔时间 time-between-eviction-runs-millis: 60000 # 配置连接在池中的最小生存时间 min-evictable-idle-time-millis: 300000 validation-query: select '1' from dual test-while-idle: true test-on-borrow: false test-on-return: false # 打开PSCache,并且指定每个连接上PSCache的大小 pool-prepared-statements: true max-open-prepared-statements: 20 max-pool-prepared-statement-per-connection-size: 20 # 配置监控统计拦截的filters, 去掉后监控界面sql无法统计, 'wall'用于防火墙 filters: stat # Spring监控AOP切入点,如x.y.z.service.*,配置多个英文逗号分隔 aop-patterns: com.springboot.servie.* # WebStatFilter配置 web-stat-filter: enabled: true # 添加过滤规则 url-pattern: /* # 忽略过滤的格式 exclusions: '*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*' # StatViewServlet配置 stat-view-servlet: enabled: true # 访问路径为/druid时,跳转到StatViewServlet url-pattern: /druid/* # 是否能够重置数据 reset-enable: false # 需要账号密码才能访问控制台 login-username: druid login-password: druid123 # IP白名单 # allow: 127.0.0.1 # IP黑名单(共同存在时,deny优先于allow) # deny: 192.168.1.218 # 配置StatFilter filter: stat: log-slow-sql: true thymeleaf: cache: false mybatis: # type-aliases扫描路径 type-aliases-package: com.springboot.pojo # mapper xml实现扫描路径 mapper-locations: classpath:mapper/*.xml property: order: BEFORE ================================================ FILE: 15.Spring-Boot-Shiro-Ehcache/src/main/resources/config/shiro-ehcache.xml ================================================ ================================================ FILE: 15.Spring-Boot-Shiro-Ehcache/src/main/resources/init.sql ================================================ -- ---------------------------- -- Table structure for T_PERMISSION -- ---------------------------- CREATE TABLE T_PERMISSION ( ID NUMBER(10) NOT NULL , URL VARCHAR2(256 BYTE) NULL , NAME VARCHAR2(64 BYTE) NULL ); COMMENT ON COLUMN T_PERMISSION.URL IS 'url地址'; COMMENT ON COLUMN T_PERMISSION.NAME IS 'url描述'; -- ---------------------------- -- Records of T_PERMISSION -- ---------------------------- INSERT INTO T_PERMISSION VALUES ('1', '/user', 'user:user'); INSERT INTO T_PERMISSION VALUES ('2', '/user/add', 'user:add'); INSERT INTO T_PERMISSION VALUES ('3', '/user/delete', 'user:delete'); -- ---------------------------- -- Table structure for T_ROLE -- ---------------------------- CREATE TABLE T_ROLE ( ID NUMBER NOT NULL , NAME VARCHAR2(32 BYTE) NULL , MEMO VARCHAR2(32 BYTE) NULL ); COMMENT ON COLUMN T_ROLE.NAME IS '角色名称'; COMMENT ON COLUMN T_ROLE.MEMO IS '角色描述'; -- ---------------------------- -- Records of T_ROLE -- ---------------------------- INSERT INTO T_ROLE VALUES ('1', 'admin', '超级管理员'); INSERT INTO T_ROLE VALUES ('2', 'test', '测试账户'); -- ---------------------------- -- Table structure for T_ROLE_PERMISSION -- ---------------------------- CREATE TABLE T_ROLE_PERMISSION ( RID NUMBER(10) NULL , PID NUMBER(10) NULL ); COMMENT ON COLUMN T_ROLE_PERMISSION.RID IS '角色id'; COMMENT ON COLUMN T_ROLE_PERMISSION.PID IS '权限id'; -- ---------------------------- -- Records of T_ROLE_PERMISSION -- ---------------------------- INSERT INTO T_ROLE_PERMISSION VALUES ('1', '2'); INSERT INTO T_ROLE_PERMISSION VALUES ('1', '3'); INSERT INTO T_ROLE_PERMISSION VALUES ('2', '1'); INSERT INTO T_ROLE_PERMISSION VALUES ('1', '1'); -- ---------------------------- -- Table structure for T_USER -- ---------------------------- CREATE TABLE T_USER ( ID NUMBER NOT NULL , USERNAME VARCHAR2(20 BYTE) NOT NULL , PASSWD VARCHAR2(128 BYTE) NOT NULL , CREATE_TIME DATE NULL , STATUS CHAR(1 BYTE) NOT NULL ); COMMENT ON COLUMN T_USER.USERNAME IS '用户名'; COMMENT ON COLUMN T_USER.PASSWD IS '密码'; COMMENT ON COLUMN T_USER.CREATE_TIME IS '创建时间'; COMMENT ON COLUMN T_USER.STATUS IS '是否有效 1:有效 0:锁定'; -- ---------------------------- -- Records of T_USER -- ---------------------------- INSERT INTO T_USER VALUES ('2', 'tester', '243e29429b340192700677d48c09d992', TO_DATE('2017-12-11 17:20:21', 'YYYY-MM-DD HH24:MI:SS'), '1'); INSERT INTO T_USER VALUES ('1', 'mrbird', '42ee25d1e43e9f57119a00d0a39e5250', TO_DATE('2017-12-11 10:52:48', 'YYYY-MM-DD HH24:MI:SS'), '1'); -- ---------------------------- -- Table structure for T_USER_ROLE -- ---------------------------- CREATE TABLE T_USER_ROLE ( USER_ID NUMBER(10) NULL , RID NUMBER(10) NULL ); COMMENT ON COLUMN T_USER_ROLE.USER_ID IS '用户id'; COMMENT ON COLUMN T_USER_ROLE.RID IS '角色id'; -- ---------------------------- -- Records of T_USER_ROLE -- ---------------------------- INSERT INTO T_USER_ROLE VALUES ('1', '1'); INSERT INTO T_USER_ROLE VALUES ('2', '2'); ================================================ FILE: 15.Spring-Boot-Shiro-Ehcache/src/main/resources/mapper/UserMapper.xml ================================================ ================================================ FILE: 15.Spring-Boot-Shiro-Ehcache/src/main/resources/mapper/UserPermissionMapper.xml ================================================ ================================================ FILE: 15.Spring-Boot-Shiro-Ehcache/src/main/resources/mapper/UserRoleMapper.xml ================================================ ================================================ FILE: 15.Spring-Boot-Shiro-Ehcache/src/main/resources/static/css/login.css ================================================ .login-page { width: 360px; padding: 8% 0 0; margin: auto; } .form { position: relative; z-index: 1; background: #ffffff; max-width: 360px; margin: 0 auto 100px; padding: 45px; text-align: center; box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.2), 0 5px 5px 0 rgba(0, 0, 0, 0.24); } .form input { outline: 0; background: #f2f2f2; width: 100%; border: 0; margin: 0 0 15px; padding: 15px; box-sizing: border-box; font-size: 14px; } .form button { text-transform: uppercase; outline: 0; background: #4caf50; width: 100%; border: 0; padding: 15px; color: #ffffff; font-size: 14px; -webkit-transition: all 0.3 ease; transition: all 0.3 ease; cursor: pointer; } .form button:hover, .form button:active, .form button:focus { background: #43a047; } .form .message { margin: 15px 0 0; color: #b3b3b3; font-size: 12px; } .form .message a { color: #4caf50; text-decoration: none; } .form .register-form { display: none; } .form p { text-align: left; margin: 0; font-size: 13px; } .form p input { width: auto; margin-right: 10px; } .container { position: relative; z-index: 1; max-width: 300px; margin: 0 auto; } .container:before, .container:after { content: ""; display: block; clear: both; } .container .info { margin: 50px auto; text-align: center; } .container .info h1 { margin: 0 0 15px; padding: 0; font-size: 36px; font-weight: 300; color: #1a1a1a; } .container .info span { color: #4d4d4d; font-size: 12px; } .container .info span a { color: #000000; text-decoration: none; } .container .info span .fa { color: #ef3b3a; } body { background: #76b852; /* fallback for old browsers */ background: -webkit-linear-gradient(right, #76b852, #8dc26f); background: -moz-linear-gradient(right, #76b852, #8dc26f); background: -o-linear-gradient(right, #76b852, #8dc26f); background: linear-gradient(to left, #76b852, #8dc26f); font-family: Lato,"PingFang SC","Microsoft YaHei",sans-serif; } ================================================ FILE: 15.Spring-Boot-Shiro-Ehcache/src/main/resources/templates/403.html ================================================ 暂无权限

您没有权限访问该资源!!

返回 ================================================ FILE: 15.Spring-Boot-Shiro-Ehcache/src/main/resources/templates/index.html ================================================ 首页

你好![[${user.userName}]]

权限测试链接

注销 ================================================ FILE: 15.Spring-Boot-Shiro-Ehcache/src/main/resources/templates/login.html ================================================ 登录 ================================================ FILE: 15.Spring-Boot-Shiro-Ehcache/src/main/resources/templates/user.html ================================================ [[${value}]]

[[${value}]]

返回 ================================================ FILE: 16.Spring-Boot-Shiro-Thymeleaf-Tag/pom.xml ================================================ 4.0.0 com.springboot Spring-Boot-Shiro-Thymeleaf-Tag 0.0.1-SNAPSHOT jar demo Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.9.RELEASE UTF-8 UTF-8 1.7 3.0.2.RELEASE 2.0.1 org.springframework.boot spring-boot-starter-web org.mybatis.spring.boot mybatis-spring-boot-starter 1.3.1 org.springframework.boot spring-boot-starter-thymeleaf org.apache.shiro shiro-spring 1.4.0 org.apache.shiro shiro-ehcache 1.3.2 org.springframework.boot spring-boot-starter-cache net.sf.ehcache ehcache com.github.theborakompanioni thymeleaf-extras-shiro 2.0.0 com.oracle ojdbc6 6.0 com.alibaba druid-spring-boot-starter 1.1.6 org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 16.Spring-Boot-Shiro-Thymeleaf-Tag/src/main/java/com/springboot/Application.java ================================================ package com.springboot; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class,args); } } ================================================ FILE: 16.Spring-Boot-Shiro-Thymeleaf-Tag/src/main/java/com/springboot/config/ShiroConfig.java ================================================ package com.springboot.config; import java.util.LinkedHashMap; import org.apache.shiro.cache.ehcache.EhCacheManager; import org.apache.shiro.codec.Base64; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.spring.LifecycleBeanPostProcessor; import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.CookieRememberMeManager; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.apache.shiro.web.servlet.SimpleCookie; import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.DependsOn; import com.springboot.shiro.ShiroRealm; import at.pollux.thymeleaf.shiro.dialect.ShiroDialect; @Configuration public class ShiroConfig { @Bean public EhCacheManager getEhCacheManager() { EhCacheManager em = new EhCacheManager(); em.setCacheManagerConfigFile("classpath:config/shiro-ehcache.xml"); return em; } @Bean public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager); shiroFilterFactoryBean.setLoginUrl("/login"); shiroFilterFactoryBean.setSuccessUrl("/index"); shiroFilterFactoryBean.setUnauthorizedUrl("/403"); LinkedHashMap filterChainDefinitionMap = new LinkedHashMap<>(); filterChainDefinitionMap.put("/css/**", "anon"); filterChainDefinitionMap.put("/js/**", "anon"); filterChainDefinitionMap.put("/fonts/**", "anon"); filterChainDefinitionMap.put("/img/**", "anon"); filterChainDefinitionMap.put("/druid/**", "anon"); filterChainDefinitionMap.put("/logout", "logout"); filterChainDefinitionMap.put("/", "anon"); filterChainDefinitionMap.put("/**", "user"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } @Bean public SecurityManager securityManager(){ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(shiroRealm()); securityManager.setRememberMeManager(rememberMeManager()); securityManager.setCacheManager(getEhCacheManager()); return securityManager; } @Bean(name = "lifecycleBeanPostProcessor") public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { return new LifecycleBeanPostProcessor(); } @Bean public ShiroRealm shiroRealm(){ ShiroRealm shiroRealm = new ShiroRealm(); return shiroRealm; } public SimpleCookie rememberMeCookie() { SimpleCookie cookie = new SimpleCookie("rememberMe"); cookie.setMaxAge(86400); return cookie; } public CookieRememberMeManager rememberMeManager() { CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager(); cookieRememberMeManager.setCookie(rememberMeCookie()); cookieRememberMeManager.setCipherKey(Base64.decode("4AvVhmFLUs0KTA3Kprsdag==")); return cookieRememberMeManager; } @Bean @DependsOn({"lifecycleBeanPostProcessor"}) public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() { DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator(); advisorAutoProxyCreator.setProxyTargetClass(true); return advisorAutoProxyCreator; } @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) { AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); return authorizationAttributeSourceAdvisor; } @Bean public ShiroDialect shiroDialect() { return new ShiroDialect(); } } ================================================ FILE: 16.Spring-Boot-Shiro-Thymeleaf-Tag/src/main/java/com/springboot/controller/LoginController.java ================================================ package com.springboot.controller; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.LockedAccountException; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.subject.Subject; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import com.springboot.pojo.ResponseBo; import com.springboot.pojo.User; import com.springboot.util.MD5Utils; @Controller public class LoginController { @GetMapping("/login") public String login() { return "login"; } @PostMapping("/login") @ResponseBody public ResponseBo login(String username, String password, Boolean rememberMe) { password = MD5Utils.encrypt(username, password); UsernamePasswordToken token = new UsernamePasswordToken(username, password, rememberMe); Subject subject = SecurityUtils.getSubject(); try { subject.login(token); return ResponseBo.ok(); } catch (UnknownAccountException e) { return ResponseBo.error(e.getMessage()); } catch (IncorrectCredentialsException e) { return ResponseBo.error(e.getMessage()); } catch (LockedAccountException e) { return ResponseBo.error(e.getMessage()); } catch (AuthenticationException e) { return ResponseBo.error("认证失败!"); } } @RequestMapping("/") public String redirectIndex() { return "redirect:/index"; } @GetMapping("/403") public String forbid() { return "403"; } @RequestMapping("/index") public String index(Model model) { User user = (User) SecurityUtils.getSubject().getPrincipal(); model.addAttribute("user", user); return "index"; } } ================================================ FILE: 16.Spring-Boot-Shiro-Thymeleaf-Tag/src/main/java/com/springboot/controller/UserController.java ================================================ package com.springboot.controller; import org.apache.shiro.authz.annotation.RequiresPermissions; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; @Controller @RequestMapping("/user") public class UserController { @RequiresPermissions("user:user") @RequestMapping("list") public String userList(Model model) { model.addAttribute("value", "获取用户信息"); return "user"; } @RequiresPermissions("user:add") @RequestMapping("add") public String userAdd(Model model) { model.addAttribute("value", "新增用户"); return "user"; } @RequiresPermissions("user:delete") @RequestMapping("delete") public String userDelete(Model model) { model.addAttribute("value", "删除用户"); return "user"; } } ================================================ FILE: 16.Spring-Boot-Shiro-Thymeleaf-Tag/src/main/java/com/springboot/dao/UserMapper.java ================================================ package com.springboot.dao; import org.apache.ibatis.annotations.Mapper; import com.springboot.pojo.User; @Mapper public interface UserMapper { User findByUserName(String userName); } ================================================ FILE: 16.Spring-Boot-Shiro-Thymeleaf-Tag/src/main/java/com/springboot/dao/UserPermissionMapper.java ================================================ package com.springboot.dao; import java.util.List; import org.apache.ibatis.annotations.Mapper; import com.springboot.pojo.Permission; @Mapper public interface UserPermissionMapper { List findByUserName(String userName); } ================================================ FILE: 16.Spring-Boot-Shiro-Thymeleaf-Tag/src/main/java/com/springboot/dao/UserRoleMapper.java ================================================ package com.springboot.dao; import java.util.List; import org.apache.ibatis.annotations.Mapper; import com.springboot.pojo.Role; @Mapper public interface UserRoleMapper { List findByUserName(String userName); } ================================================ FILE: 16.Spring-Boot-Shiro-Thymeleaf-Tag/src/main/java/com/springboot/handler/GlobalExceptionHandler.java ================================================ package com.springboot.handler; import org.apache.shiro.authz.AuthorizationException; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; @ControllerAdvice @Order(value = Ordered.HIGHEST_PRECEDENCE) public class GlobalExceptionHandler { @ExceptionHandler(value = AuthorizationException.class) public String handleAuthorizationException() { return "403"; } } ================================================ FILE: 16.Spring-Boot-Shiro-Thymeleaf-Tag/src/main/java/com/springboot/pojo/Permission.java ================================================ package com.springboot.pojo; import java.io.Serializable; public class Permission implements Serializable{ private static final long serialVersionUID = 7160557680614732403L; private Integer id; private String url; private String name; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getName() { return name; } public void setName(String name) { this.name = name; } } ================================================ FILE: 16.Spring-Boot-Shiro-Thymeleaf-Tag/src/main/java/com/springboot/pojo/ResponseBo.java ================================================ package com.springboot.pojo; import java.util.HashMap; import java.util.Map; public class ResponseBo extends HashMap{ private static final long serialVersionUID = 1L; public ResponseBo() { put("code", 0); put("msg", "操作成功"); } public static ResponseBo error() { return error(1, "操作失败"); } public static ResponseBo error(String msg) { return error(500, msg); } public static ResponseBo error(int code, String msg) { ResponseBo ResponseBo = new ResponseBo(); ResponseBo.put("code", code); ResponseBo.put("msg", msg); return ResponseBo; } public static ResponseBo ok(String msg) { ResponseBo ResponseBo = new ResponseBo(); ResponseBo.put("msg", msg); return ResponseBo; } public static ResponseBo ok(Map map) { ResponseBo ResponseBo = new ResponseBo(); ResponseBo.putAll(map); return ResponseBo; } public static ResponseBo ok() { return new ResponseBo(); } @Override public ResponseBo put(String key, Object value) { super.put(key, value); return this; } } ================================================ FILE: 16.Spring-Boot-Shiro-Thymeleaf-Tag/src/main/java/com/springboot/pojo/Role.java ================================================ package com.springboot.pojo; import java.io.Serializable; public class Role implements Serializable{ private static final long serialVersionUID = -227437593919820521L; private Integer id; private String name; private String memo; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getMemo() { return memo; } public void setMemo(String memo) { this.memo = memo; } } ================================================ FILE: 16.Spring-Boot-Shiro-Thymeleaf-Tag/src/main/java/com/springboot/pojo/User.java ================================================ package com.springboot.pojo; import java.io.Serializable; import java.util.Date; public class User implements Serializable{ private static final long serialVersionUID = -5440372534300871944L; private Integer id; private String userName; private String password; private Date createTime; private String status; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Date getCreateTime() { return createTime; } public void setCreateTime(Date createTime) { this.createTime = createTime; } public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } } ================================================ FILE: 16.Spring-Boot-Shiro-Thymeleaf-Tag/src/main/java/com/springboot/shiro/ShiroRealm.java ================================================ package com.springboot.shiro; import java.util.HashSet; import java.util.List; import java.util.Set; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.LockedAccountException; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.springframework.beans.factory.annotation.Autowired; import com.springboot.dao.UserMapper; import com.springboot.dao.UserPermissionMapper; import com.springboot.dao.UserRoleMapper; import com.springboot.pojo.Permission; import com.springboot.pojo.Role; import com.springboot.pojo.User; public class ShiroRealm extends AuthorizingRealm { @Autowired private UserMapper userMapper; @Autowired private UserRoleMapper userRoleMapper; @Autowired private UserPermissionMapper userPermissionMapper; /** * 获取用户角色和权限 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) { User user = (User) SecurityUtils.getSubject().getPrincipal(); String userName = user.getUserName(); System.out.println("用户" + userName + "获取权限-----ShiroRealm.doGetAuthorizationInfo"); SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(); // 获取用户角色集 List roleList = userRoleMapper.findByUserName(userName); Set roleSet = new HashSet(); for (Role r : roleList) { roleSet.add(r.getName()); } simpleAuthorizationInfo.setRoles(roleSet); // 获取用户权限集 List permissionList = userPermissionMapper.findByUserName(userName); Set permissionSet = new HashSet(); for (Permission p : permissionList) { permissionSet.add(p.getName()); } simpleAuthorizationInfo.setStringPermissions(permissionSet); return simpleAuthorizationInfo; } /** * 登录认证 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { String userName = (String) token.getPrincipal(); String password = new String((char[]) token.getCredentials()); System.out.println("用户" + userName + "认证-----ShiroRealm.doGetAuthenticationInfo"); User user = userMapper.findByUserName(userName); if (user == null) { throw new UnknownAccountException("用户名或密码错误!"); } if (!password.equals(user.getPassword())) { throw new IncorrectCredentialsException("用户名或密码错误!"); } if (user.getStatus().equals("0")) { throw new LockedAccountException("账号已被锁定,请联系管理员!"); } SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, password, getName()); return info; } } ================================================ FILE: 16.Spring-Boot-Shiro-Thymeleaf-Tag/src/main/java/com/springboot/util/MD5Utils.java ================================================ package com.springboot.util; import org.apache.shiro.crypto.hash.SimpleHash; import org.apache.shiro.util.ByteSource; public class MD5Utils { private static final String SALT = "mrbird"; private static final String ALGORITH_NAME = "md5"; private static final int HASH_ITERATIONS = 2; public static String encrypt(String pswd) { String newPassword = new SimpleHash(ALGORITH_NAME, pswd, ByteSource.Util.bytes(SALT), HASH_ITERATIONS).toHex(); return newPassword; } public static String encrypt(String username, String pswd) { String newPassword = new SimpleHash(ALGORITH_NAME, pswd, ByteSource.Util.bytes(username + SALT), HASH_ITERATIONS).toHex(); return newPassword; } public static void main(String[] args) { System.out.println(MD5Utils.encrypt("tester", "123456")); } } ================================================ FILE: 16.Spring-Boot-Shiro-Thymeleaf-Tag/src/main/resources/application.yml ================================================ server: context-path: /web spring: datasource: druid: # 数据库访问配置, 使用druid数据源 type: com.alibaba.druid.pool.DruidDataSource driver-class-name: oracle.jdbc.driver.OracleDriver url: jdbc:oracle:thin:@localhost:1521:ORCL username: test password: 123456 # 连接池配置 initial-size: 5 min-idle: 5 max-active: 20 # 连接等待超时时间 max-wait: 30000 # 配置检测可以关闭的空闲连接间隔时间 time-between-eviction-runs-millis: 60000 # 配置连接在池中的最小生存时间 min-evictable-idle-time-millis: 300000 validation-query: select '1' from dual test-while-idle: true test-on-borrow: false test-on-return: false # 打开PSCache,并且指定每个连接上PSCache的大小 pool-prepared-statements: true max-open-prepared-statements: 20 max-pool-prepared-statement-per-connection-size: 20 # 配置监控统计拦截的filters, 去掉后监控界面sql无法统计, 'wall'用于防火墙 filters: stat # Spring监控AOP切入点,如x.y.z.service.*,配置多个英文逗号分隔 aop-patterns: com.springboot.servie.* # WebStatFilter配置 web-stat-filter: enabled: true # 添加过滤规则 url-pattern: /* # 忽略过滤的格式 exclusions: '*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*' # StatViewServlet配置 stat-view-servlet: enabled: true # 访问路径为/druid时,跳转到StatViewServlet url-pattern: /druid/* # 是否能够重置数据 reset-enable: false # 需要账号密码才能访问控制台 login-username: druid login-password: druid123 # IP白名单 # allow: 127.0.0.1 # IP黑名单(共同存在时,deny优先于allow) # deny: 192.168.1.218 # 配置StatFilter filter: stat: log-slow-sql: true thymeleaf: cache: false mybatis: # type-aliases扫描路径 type-aliases-package: com.springboot.pojo # mapper xml实现扫描路径 mapper-locations: classpath:mapper/*.xml property: order: BEFORE ================================================ FILE: 16.Spring-Boot-Shiro-Thymeleaf-Tag/src/main/resources/config/shiro-ehcache.xml ================================================ ================================================ FILE: 16.Spring-Boot-Shiro-Thymeleaf-Tag/src/main/resources/init.sql ================================================ -- ---------------------------- -- Table structure for T_PERMISSION -- ---------------------------- CREATE TABLE T_PERMISSION ( ID NUMBER(10) NOT NULL , URL VARCHAR2(256 BYTE) NULL , NAME VARCHAR2(64 BYTE) NULL ); COMMENT ON COLUMN T_PERMISSION.URL IS 'url地址'; COMMENT ON COLUMN T_PERMISSION.NAME IS 'url描述'; -- ---------------------------- -- Records of T_PERMISSION -- ---------------------------- INSERT INTO T_PERMISSION VALUES ('1', '/user', 'user:user'); INSERT INTO T_PERMISSION VALUES ('2', '/user/add', 'user:add'); INSERT INTO T_PERMISSION VALUES ('3', '/user/delete', 'user:delete'); -- ---------------------------- -- Table structure for T_ROLE -- ---------------------------- CREATE TABLE T_ROLE ( ID NUMBER NOT NULL , NAME VARCHAR2(32 BYTE) NULL , MEMO VARCHAR2(32 BYTE) NULL ); COMMENT ON COLUMN T_ROLE.NAME IS '角色名称'; COMMENT ON COLUMN T_ROLE.MEMO IS '角色描述'; -- ---------------------------- -- Records of T_ROLE -- ---------------------------- INSERT INTO T_ROLE VALUES ('1', 'admin', '超级管理员'); INSERT INTO T_ROLE VALUES ('2', 'test', '测试账户'); -- ---------------------------- -- Table structure for T_ROLE_PERMISSION -- ---------------------------- CREATE TABLE T_ROLE_PERMISSION ( RID NUMBER(10) NULL , PID NUMBER(10) NULL ); COMMENT ON COLUMN T_ROLE_PERMISSION.RID IS '角色id'; COMMENT ON COLUMN T_ROLE_PERMISSION.PID IS '权限id'; -- ---------------------------- -- Records of T_ROLE_PERMISSION -- ---------------------------- INSERT INTO T_ROLE_PERMISSION VALUES ('1', '2'); INSERT INTO T_ROLE_PERMISSION VALUES ('1', '3'); INSERT INTO T_ROLE_PERMISSION VALUES ('2', '1'); INSERT INTO T_ROLE_PERMISSION VALUES ('1', '1'); -- ---------------------------- -- Table structure for T_USER -- ---------------------------- CREATE TABLE T_USER ( ID NUMBER NOT NULL , USERNAME VARCHAR2(20 BYTE) NOT NULL , PASSWD VARCHAR2(128 BYTE) NOT NULL , CREATE_TIME DATE NULL , STATUS CHAR(1 BYTE) NOT NULL ); COMMENT ON COLUMN T_USER.USERNAME IS '用户名'; COMMENT ON COLUMN T_USER.PASSWD IS '密码'; COMMENT ON COLUMN T_USER.CREATE_TIME IS '创建时间'; COMMENT ON COLUMN T_USER.STATUS IS '是否有效 1:有效 0:锁定'; -- ---------------------------- -- Records of T_USER -- ---------------------------- INSERT INTO T_USER VALUES ('2', 'tester', '243e29429b340192700677d48c09d992', TO_DATE('2017-12-11 17:20:21', 'YYYY-MM-DD HH24:MI:SS'), '1'); INSERT INTO T_USER VALUES ('1', 'mrbird', '42ee25d1e43e9f57119a00d0a39e5250', TO_DATE('2017-12-11 10:52:48', 'YYYY-MM-DD HH24:MI:SS'), '1'); -- ---------------------------- -- Table structure for T_USER_ROLE -- ---------------------------- CREATE TABLE T_USER_ROLE ( USER_ID NUMBER(10) NULL , RID NUMBER(10) NULL ); COMMENT ON COLUMN T_USER_ROLE.USER_ID IS '用户id'; COMMENT ON COLUMN T_USER_ROLE.RID IS '角色id'; -- ---------------------------- -- Records of T_USER_ROLE -- ---------------------------- INSERT INTO T_USER_ROLE VALUES ('1', '1'); INSERT INTO T_USER_ROLE VALUES ('2', '2'); ================================================ FILE: 16.Spring-Boot-Shiro-Thymeleaf-Tag/src/main/resources/mapper/UserMapper.xml ================================================ ================================================ FILE: 16.Spring-Boot-Shiro-Thymeleaf-Tag/src/main/resources/mapper/UserPermissionMapper.xml ================================================ ================================================ FILE: 16.Spring-Boot-Shiro-Thymeleaf-Tag/src/main/resources/mapper/UserRoleMapper.xml ================================================ ================================================ FILE: 16.Spring-Boot-Shiro-Thymeleaf-Tag/src/main/resources/static/css/login.css ================================================ .login-page { width: 360px; padding: 8% 0 0; margin: auto; } .form { position: relative; z-index: 1; background: #ffffff; max-width: 360px; margin: 0 auto 100px; padding: 45px; text-align: center; box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.2), 0 5px 5px 0 rgba(0, 0, 0, 0.24); } .form input { outline: 0; background: #f2f2f2; width: 100%; border: 0; margin: 0 0 15px; padding: 15px; box-sizing: border-box; font-size: 14px; } .form button { text-transform: uppercase; outline: 0; background: #4caf50; width: 100%; border: 0; padding: 15px; color: #ffffff; font-size: 14px; -webkit-transition: all 0.3 ease; transition: all 0.3 ease; cursor: pointer; } .form button:hover, .form button:active, .form button:focus { background: #43a047; } .form .message { margin: 15px 0 0; color: #b3b3b3; font-size: 12px; } .form .message a { color: #4caf50; text-decoration: none; } .form .register-form { display: none; } .form p { text-align: left; margin: 0; font-size: 13px; } .form p input { width: auto; margin-right: 10px; } .container { position: relative; z-index: 1; max-width: 300px; margin: 0 auto; } .container:before, .container:after { content: ""; display: block; clear: both; } .container .info { margin: 50px auto; text-align: center; } .container .info h1 { margin: 0 0 15px; padding: 0; font-size: 36px; font-weight: 300; color: #1a1a1a; } .container .info span { color: #4d4d4d; font-size: 12px; } .container .info span a { color: #000000; text-decoration: none; } .container .info span .fa { color: #ef3b3a; } body { background: #76b852; /* fallback for old browsers */ background: -webkit-linear-gradient(right, #76b852, #8dc26f); background: -moz-linear-gradient(right, #76b852, #8dc26f); background: -o-linear-gradient(right, #76b852, #8dc26f); background: linear-gradient(to left, #76b852, #8dc26f); font-family: Lato,"PingFang SC","Microsoft YaHei",sans-serif; } ================================================ FILE: 16.Spring-Boot-Shiro-Thymeleaf-Tag/src/main/resources/templates/403.html ================================================ 暂无权限

您没有权限访问该资源!!

返回 ================================================ FILE: 16.Spring-Boot-Shiro-Thymeleaf-Tag/src/main/resources/templates/index.html ================================================ 首页

你好![[${user.userName}]]

你的角色为超级管理员

你的角色为测试账户

注销 ================================================ FILE: 16.Spring-Boot-Shiro-Thymeleaf-Tag/src/main/resources/templates/login.html ================================================ 登录 ================================================ FILE: 16.Spring-Boot-Shiro-Thymeleaf-Tag/src/main/resources/templates/user.html ================================================ [[${value}]]

[[${value}]]

返回 ================================================ FILE: 17.Spring-Boot-Shiro-Session/pom.xml ================================================ 4.0.0 com.springboot demo 0.0.1-SNAPSHOT jar demo Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.9.RELEASE UTF-8 UTF-8 1.7 3.0.2.RELEASE 2.0.1 org.springframework.boot spring-boot-starter-web org.mybatis.spring.boot mybatis-spring-boot-starter 1.3.1 org.springframework.boot spring-boot-starter-thymeleaf org.apache.shiro shiro-spring 1.4.0 org.apache.shiro shiro-ehcache 1.3.2 org.springframework.boot spring-boot-starter-cache net.sf.ehcache ehcache com.github.theborakompanioni thymeleaf-extras-shiro 2.0.0 com.oracle ojdbc6 6.0 com.alibaba druid-spring-boot-starter 1.1.6 org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 17.Spring-Boot-Shiro-Session/src/main/java/com/springboot/Application.java ================================================ package com.springboot; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class,args); } } ================================================ FILE: 17.Spring-Boot-Shiro-Session/src/main/java/com/springboot/config/ShiroConfig.java ================================================ package com.springboot.config; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedHashMap; import org.apache.shiro.cache.ehcache.EhCacheManager; import org.apache.shiro.codec.Base64; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.session.SessionListener; import org.apache.shiro.session.mgt.SessionManager; import org.apache.shiro.session.mgt.eis.MemorySessionDAO; import org.apache.shiro.session.mgt.eis.SessionDAO; import org.apache.shiro.spring.LifecycleBeanPostProcessor; import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.CookieRememberMeManager; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.apache.shiro.web.servlet.SimpleCookie; import org.apache.shiro.web.session.mgt.DefaultWebSessionManager; import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.DependsOn; import com.springboot.listener.ShiroSessionListener; import com.springboot.shiro.ShiroRealm; import at.pollux.thymeleaf.shiro.dialect.ShiroDialect; @Configuration public class ShiroConfig { @Bean public EhCacheManager getEhCacheManager() { EhCacheManager em = new EhCacheManager(); em.setCacheManagerConfigFile("classpath:config/shiro-ehcache.xml"); return em; } @Bean public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager); shiroFilterFactoryBean.setLoginUrl("/login"); shiroFilterFactoryBean.setSuccessUrl("/index"); shiroFilterFactoryBean.setUnauthorizedUrl("/403"); LinkedHashMap filterChainDefinitionMap = new LinkedHashMap<>(); filterChainDefinitionMap.put("/css/**", "anon"); filterChainDefinitionMap.put("/js/**", "anon"); filterChainDefinitionMap.put("/fonts/**", "anon"); filterChainDefinitionMap.put("/img/**", "anon"); filterChainDefinitionMap.put("/druid/**", "anon"); filterChainDefinitionMap.put("/logout", "logout"); filterChainDefinitionMap.put("/", "anon"); filterChainDefinitionMap.put("/**", "user"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } @Bean public SecurityManager securityManager(){ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(shiroRealm()); securityManager.setRememberMeManager(rememberMeManager()); securityManager.setCacheManager(getEhCacheManager()); securityManager.setSessionManager(sessionManager()); return securityManager; } @Bean(name = "lifecycleBeanPostProcessor") public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { return new LifecycleBeanPostProcessor(); } @Bean public ShiroRealm shiroRealm(){ ShiroRealm shiroRealm = new ShiroRealm(); return shiroRealm; } public SimpleCookie rememberMeCookie() { SimpleCookie cookie = new SimpleCookie("rememberMe"); cookie.setMaxAge(86400); return cookie; } public CookieRememberMeManager rememberMeManager() { CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager(); cookieRememberMeManager.setCookie(rememberMeCookie()); cookieRememberMeManager.setCipherKey(Base64.decode("4AvVhmFLUs0KTA3Kprsdag==")); return cookieRememberMeManager; } @Bean @DependsOn({"lifecycleBeanPostProcessor"}) public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() { DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator(); advisorAutoProxyCreator.setProxyTargetClass(true); return advisorAutoProxyCreator; } @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) { AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); return authorizationAttributeSourceAdvisor; } @Bean public ShiroDialect shiroDialect() { return new ShiroDialect(); } @Bean public SessionDAO sessionDAO() { MemorySessionDAO sessionDAO = new MemorySessionDAO(); return sessionDAO; } @Bean public SessionManager sessionManager() { DefaultWebSessionManager sessionManager = new DefaultWebSessionManager(); Collection listeners = new ArrayList(); listeners.add(new ShiroSessionListener()); sessionManager.setSessionListeners(listeners); sessionManager.setSessionDAO(sessionDAO()); return sessionManager; } } ================================================ FILE: 17.Spring-Boot-Shiro-Session/src/main/java/com/springboot/controller/LoginController.java ================================================ package com.springboot.controller; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.LockedAccountException; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.subject.Subject; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import com.springboot.pojo.ResponseBo; import com.springboot.pojo.User; import com.springboot.util.MD5Utils; @Controller public class LoginController { @GetMapping("/login") public String login() { return "login"; } @PostMapping("/login") @ResponseBody public ResponseBo login(String username, String password, Boolean rememberMe) { password = MD5Utils.encrypt(username, password); UsernamePasswordToken token = new UsernamePasswordToken(username, password, rememberMe); Subject subject = SecurityUtils.getSubject(); try { subject.login(token); return ResponseBo.ok(); } catch (UnknownAccountException e) { return ResponseBo.error(e.getMessage()); } catch (IncorrectCredentialsException e) { return ResponseBo.error(e.getMessage()); } catch (LockedAccountException e) { return ResponseBo.error(e.getMessage()); } catch (AuthenticationException e) { return ResponseBo.error("认证失败!"); } } @RequestMapping("/") public String redirectIndex() { return "redirect:/index"; } @GetMapping("/403") public String forbid() { return "403"; } @RequestMapping("/index") public String index(Model model) { User user = (User) SecurityUtils.getSubject().getPrincipal(); model.addAttribute("user", user); return "index"; } } ================================================ FILE: 17.Spring-Boot-Shiro-Session/src/main/java/com/springboot/controller/SessionController.java ================================================ package com.springboot.controller; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import com.springboot.pojo.ResponseBo; import com.springboot.pojo.UserOnline; import com.springboot.service.SessionService; @Controller @RequestMapping("/online") public class SessionController { @Autowired SessionService sessionService; @RequestMapping("index") public String online() { return "online"; } @ResponseBody @RequestMapping("list") public List list() { return sessionService.list(); } @ResponseBody @RequestMapping("forceLogout") public ResponseBo forceLogout(String id) { try { sessionService.forceLogout(id); return ResponseBo.ok(); } catch (Exception e) { e.printStackTrace(); return ResponseBo.error("踢出用户失败"); } } } ================================================ FILE: 17.Spring-Boot-Shiro-Session/src/main/java/com/springboot/controller/UserController.java ================================================ package com.springboot.controller; import org.apache.shiro.authz.annotation.RequiresPermissions; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; @Controller @RequestMapping("/user") public class UserController { @RequiresPermissions("user:user") @RequestMapping("list") public String userList(Model model) { model.addAttribute("value", "获取用户信息"); return "user"; } @RequiresPermissions("user:add") @RequestMapping("add") public String userAdd(Model model) { model.addAttribute("value", "新增用户"); return "user"; } @RequiresPermissions("user:delete") @RequestMapping("delete") public String userDelete(Model model) { model.addAttribute("value", "删除用户"); return "user"; } } ================================================ FILE: 17.Spring-Boot-Shiro-Session/src/main/java/com/springboot/dao/UserMapper.java ================================================ package com.springboot.dao; import org.apache.ibatis.annotations.Mapper; import com.springboot.pojo.User; @Mapper public interface UserMapper { User findByUserName(String userName); } ================================================ FILE: 17.Spring-Boot-Shiro-Session/src/main/java/com/springboot/dao/UserPermissionMapper.java ================================================ package com.springboot.dao; import java.util.List; import org.apache.ibatis.annotations.Mapper; import com.springboot.pojo.Permission; @Mapper public interface UserPermissionMapper { List findByUserName(String userName); } ================================================ FILE: 17.Spring-Boot-Shiro-Session/src/main/java/com/springboot/dao/UserRoleMapper.java ================================================ package com.springboot.dao; import java.util.List; import org.apache.ibatis.annotations.Mapper; import com.springboot.pojo.Role; @Mapper public interface UserRoleMapper { List findByUserName(String userName); } ================================================ FILE: 17.Spring-Boot-Shiro-Session/src/main/java/com/springboot/handler/GlobalExceptionHandler.java ================================================ package com.springboot.handler; import org.apache.shiro.authz.AuthorizationException; import org.apache.shiro.session.ExpiredSessionException; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; @ControllerAdvice @Order(value = Ordered.HIGHEST_PRECEDENCE) public class GlobalExceptionHandler { @ExceptionHandler(value = AuthorizationException.class) public String handleAuthorizationException() { return "403"; } @ExceptionHandler(value = ExpiredSessionException.class ) public String handleExpiredSessionException() { return "login"; } } ================================================ FILE: 17.Spring-Boot-Shiro-Session/src/main/java/com/springboot/listener/ShiroSessionListener.java ================================================ package com.springboot.listener; import java.util.concurrent.atomic.AtomicInteger; import org.apache.shiro.session.Session; import org.apache.shiro.session.SessionListener; public class ShiroSessionListener implements SessionListener{ private final AtomicInteger sessionCount = new AtomicInteger(0); @Override public void onStart(Session session) { sessionCount.incrementAndGet(); } @Override public void onStop(Session session) { sessionCount.decrementAndGet(); } @Override public void onExpiration(Session session) { sessionCount.decrementAndGet(); } } ================================================ FILE: 17.Spring-Boot-Shiro-Session/src/main/java/com/springboot/pojo/Permission.java ================================================ package com.springboot.pojo; import java.io.Serializable; public class Permission implements Serializable{ private static final long serialVersionUID = 7160557680614732403L; private Integer id; private String url; private String name; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getName() { return name; } public void setName(String name) { this.name = name; } } ================================================ FILE: 17.Spring-Boot-Shiro-Session/src/main/java/com/springboot/pojo/ResponseBo.java ================================================ package com.springboot.pojo; import java.util.HashMap; import java.util.Map; public class ResponseBo extends HashMap{ private static final long serialVersionUID = 1L; public ResponseBo() { put("code", 0); put("msg", "操作成功"); } public static ResponseBo error() { return error(1, "操作失败"); } public static ResponseBo error(String msg) { return error(500, msg); } public static ResponseBo error(int code, String msg) { ResponseBo ResponseBo = new ResponseBo(); ResponseBo.put("code", code); ResponseBo.put("msg", msg); return ResponseBo; } public static ResponseBo ok(String msg) { ResponseBo ResponseBo = new ResponseBo(); ResponseBo.put("msg", msg); return ResponseBo; } public static ResponseBo ok(Map map) { ResponseBo ResponseBo = new ResponseBo(); ResponseBo.putAll(map); return ResponseBo; } public static ResponseBo ok() { return new ResponseBo(); } @Override public ResponseBo put(String key, Object value) { super.put(key, value); return this; } } ================================================ FILE: 17.Spring-Boot-Shiro-Session/src/main/java/com/springboot/pojo/Role.java ================================================ package com.springboot.pojo; import java.io.Serializable; public class Role implements Serializable{ private static final long serialVersionUID = -227437593919820521L; private Integer id; private String name; private String memo; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getMemo() { return memo; } public void setMemo(String memo) { this.memo = memo; } } ================================================ FILE: 17.Spring-Boot-Shiro-Session/src/main/java/com/springboot/pojo/User.java ================================================ package com.springboot.pojo; import java.io.Serializable; import java.util.Date; public class User implements Serializable{ private static final long serialVersionUID = -5440372534300871944L; private Integer id; private String userName; private String password; private Date createTime; private String status; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Date getCreateTime() { return createTime; } public void setCreateTime(Date createTime) { this.createTime = createTime; } public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } } ================================================ FILE: 17.Spring-Boot-Shiro-Session/src/main/java/com/springboot/pojo/UserOnline.java ================================================ package com.springboot.pojo; import java.io.Serializable; import java.util.Date; public class UserOnline implements Serializable{ private static final long serialVersionUID = 3828664348416633856L; // session id private String id; // 用户id private String userId; // 用户名称 private String username; // 用户主机地址 private String host; // 用户登录时系统IP private String systemHost; // 状态 private String status; // session创建时间 private Date startTimestamp; // session最后访问时间 private Date lastAccessTime; // 超时时间 private Long timeout; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getUserId() { return userId; } public void setUserId(String userId) { this.userId = userId; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getHost() { return host; } public void setHost(String host) { this.host = host; } public String getSystemHost() { return systemHost; } public void setSystemHost(String systemHost) { this.systemHost = systemHost; } public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } public Date getStartTimestamp() { return startTimestamp; } public void setStartTimestamp(Date startTimestamp) { this.startTimestamp = startTimestamp; } public Date getLastAccessTime() { return lastAccessTime; } public void setLastAccessTime(Date lastAccessTime) { this.lastAccessTime = lastAccessTime; } public Long getTimeout() { return timeout; } public void setTimeout(Long timeout) { this.timeout = timeout; } } ================================================ FILE: 17.Spring-Boot-Shiro-Session/src/main/java/com/springboot/service/SessionService.java ================================================ package com.springboot.service; import java.util.List; import com.springboot.pojo.UserOnline; public interface SessionService { List list(); boolean forceLogout(String sessionId); } ================================================ FILE: 17.Spring-Boot-Shiro-Session/src/main/java/com/springboot/service/impl/SessionServiceImpl.java ================================================ package com.springboot.service.impl; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.apache.shiro.session.Session; import org.apache.shiro.session.mgt.eis.SessionDAO; import org.apache.shiro.subject.SimplePrincipalCollection; import org.apache.shiro.subject.support.DefaultSubjectContext; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.springboot.pojo.User; import com.springboot.pojo.UserOnline; import com.springboot.service.SessionService; @Service("sessionService") public class SessionServiceImpl implements SessionService { @Autowired private SessionDAO sessionDAO; @Override public List list() { List list = new ArrayList<>(); Collection sessions = sessionDAO.getActiveSessions(); for (Session session : sessions) { UserOnline userOnline = new UserOnline(); User user = new User(); SimplePrincipalCollection principalCollection = new SimplePrincipalCollection(); if (session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY) == null) { continue; } else { principalCollection = (SimplePrincipalCollection) session .getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY); user = (User) principalCollection.getPrimaryPrincipal(); userOnline.setUsername(user.getUserName()); userOnline.setUserId(user.getId().toString()); } userOnline.setId((String) session.getId()); userOnline.setHost(session.getHost()); userOnline.setStartTimestamp(session.getStartTimestamp()); userOnline.setLastAccessTime(session.getLastAccessTime()); Long timeout = session.getTimeout(); if (timeout == 0l) { userOnline.setStatus("离线"); } else { userOnline.setStatus("在线"); } userOnline.setTimeout(timeout); list.add(userOnline); } return list; } @Override public boolean forceLogout(String sessionId) { Session session = sessionDAO.readSession(sessionId); session.setTimeout(0); return true; } } ================================================ FILE: 17.Spring-Boot-Shiro-Session/src/main/java/com/springboot/shiro/ShiroRealm.java ================================================ package com.springboot.shiro; import java.util.HashSet; import java.util.List; import java.util.Set; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.LockedAccountException; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.springframework.beans.factory.annotation.Autowired; import com.springboot.dao.UserMapper; import com.springboot.dao.UserPermissionMapper; import com.springboot.dao.UserRoleMapper; import com.springboot.pojo.Permission; import com.springboot.pojo.Role; import com.springboot.pojo.User; public class ShiroRealm extends AuthorizingRealm { @Autowired private UserMapper userMapper; @Autowired private UserRoleMapper userRoleMapper; @Autowired private UserPermissionMapper userPermissionMapper; /** * 获取用户角色和权限 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) { User user = (User) SecurityUtils.getSubject().getPrincipal(); String userName = user.getUserName(); System.out.println("用户" + userName + "获取权限-----ShiroRealm.doGetAuthorizationInfo"); SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(); // 获取用户角色集 List roleList = userRoleMapper.findByUserName(userName); Set roleSet = new HashSet(); for (Role r : roleList) { roleSet.add(r.getName()); } simpleAuthorizationInfo.setRoles(roleSet); // 获取用户权限集 List permissionList = userPermissionMapper.findByUserName(userName); Set permissionSet = new HashSet(); for (Permission p : permissionList) { permissionSet.add(p.getName()); } simpleAuthorizationInfo.setStringPermissions(permissionSet); return simpleAuthorizationInfo; } /** * 登录认证 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { String userName = (String) token.getPrincipal(); String password = new String((char[]) token.getCredentials()); System.out.println("用户" + userName + "认证-----ShiroRealm.doGetAuthenticationInfo"); User user = userMapper.findByUserName(userName); if (user == null) { throw new UnknownAccountException("用户名或密码错误!"); } if (!password.equals(user.getPassword())) { throw new IncorrectCredentialsException("用户名或密码错误!"); } if (user.getStatus().equals("0")) { throw new LockedAccountException("账号已被锁定,请联系管理员!"); } SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, password, getName()); return info; } } ================================================ FILE: 17.Spring-Boot-Shiro-Session/src/main/java/com/springboot/util/MD5Utils.java ================================================ package com.springboot.util; import org.apache.shiro.crypto.hash.SimpleHash; import org.apache.shiro.util.ByteSource; public class MD5Utils { private static final String SALT = "mrbird"; private static final String ALGORITH_NAME = "md5"; private static final int HASH_ITERATIONS = 2; public static String encrypt(String pswd) { String newPassword = new SimpleHash(ALGORITH_NAME, pswd, ByteSource.Util.bytes(SALT), HASH_ITERATIONS).toHex(); return newPassword; } public static String encrypt(String username, String pswd) { String newPassword = new SimpleHash(ALGORITH_NAME, pswd, ByteSource.Util.bytes(username + SALT), HASH_ITERATIONS).toHex(); return newPassword; } public static void main(String[] args) { System.out.println(MD5Utils.encrypt("tester", "123456")); } } ================================================ FILE: 17.Spring-Boot-Shiro-Session/src/main/resources/application.yml ================================================ server: context-path: /web spring: datasource: druid: # 数据库访问配置, 使用druid数据源 type: com.alibaba.druid.pool.DruidDataSource driver-class-name: oracle.jdbc.driver.OracleDriver url: jdbc:oracle:thin:@localhost:1521:ORCL username: scott password: 6742530 # 连接池配置 initial-size: 5 min-idle: 5 max-active: 20 # 连接等待超时时间 max-wait: 30000 # 配置检测可以关闭的空闲连接间隔时间 time-between-eviction-runs-millis: 60000 # 配置连接在池中的最小生存时间 min-evictable-idle-time-millis: 300000 validation-query: select '1' from dual test-while-idle: true test-on-borrow: false test-on-return: false # 打开PSCache,并且指定每个连接上PSCache的大小 pool-prepared-statements: true max-open-prepared-statements: 20 max-pool-prepared-statement-per-connection-size: 20 # 配置监控统计拦截的filters, 去掉后监控界面sql无法统计, 'wall'用于防火墙 filters: stat # Spring监控AOP切入点,如x.y.z.service.*,配置多个英文逗号分隔 aop-patterns: com.springboot.servie.* # WebStatFilter配置 web-stat-filter: enabled: true # 添加过滤规则 url-pattern: /* # 忽略过滤的格式 exclusions: '*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*' # StatViewServlet配置 stat-view-servlet: enabled: true # 访问路径为/druid时,跳转到StatViewServlet url-pattern: /druid/* # 是否能够重置数据 reset-enable: false # 需要账号密码才能访问控制台 login-username: druid login-password: druid123 # IP白名单 # allow: 127.0.0.1 # IP黑名单(共同存在时,deny优先于allow) # deny: 192.168.1.218 # 配置StatFilter filter: stat: log-slow-sql: true thymeleaf: cache: false mybatis: # type-aliases扫描路径 type-aliases-package: com.springboot.pojo # mapper xml实现扫描路径 mapper-locations: classpath:mapper/*.xml property: order: BEFORE ================================================ FILE: 17.Spring-Boot-Shiro-Session/src/main/resources/config/shiro-ehcache.xml ================================================ ================================================ FILE: 17.Spring-Boot-Shiro-Session/src/main/resources/init.sql ================================================ -- ---------------------------- -- Table structure for T_PERMISSION -- ---------------------------- CREATE TABLE T_PERMISSION ( ID NUMBER(10) NOT NULL , URL VARCHAR2(256 BYTE) NULL , NAME VARCHAR2(64 BYTE) NULL ); COMMENT ON COLUMN T_PERMISSION.URL IS 'url地址'; COMMENT ON COLUMN T_PERMISSION.NAME IS 'url描述'; -- ---------------------------- -- Records of T_PERMISSION -- ---------------------------- INSERT INTO T_PERMISSION VALUES ('1', '/user', 'user:user'); INSERT INTO T_PERMISSION VALUES ('2', '/user/add', 'user:add'); INSERT INTO T_PERMISSION VALUES ('3', '/user/delete', 'user:delete'); -- ---------------------------- -- Table structure for T_ROLE -- ---------------------------- CREATE TABLE T_ROLE ( ID NUMBER NOT NULL , NAME VARCHAR2(32 BYTE) NULL , MEMO VARCHAR2(32 BYTE) NULL ); COMMENT ON COLUMN T_ROLE.NAME IS '角色名称'; COMMENT ON COLUMN T_ROLE.MEMO IS '角色描述'; -- ---------------------------- -- Records of T_ROLE -- ---------------------------- INSERT INTO T_ROLE VALUES ('1', 'admin', '超级管理员'); INSERT INTO T_ROLE VALUES ('2', 'test', '测试账户'); -- ---------------------------- -- Table structure for T_ROLE_PERMISSION -- ---------------------------- CREATE TABLE T_ROLE_PERMISSION ( RID NUMBER(10) NULL , PID NUMBER(10) NULL ); COMMENT ON COLUMN T_ROLE_PERMISSION.RID IS '角色id'; COMMENT ON COLUMN T_ROLE_PERMISSION.PID IS '权限id'; -- ---------------------------- -- Records of T_ROLE_PERMISSION -- ---------------------------- INSERT INTO T_ROLE_PERMISSION VALUES ('1', '2'); INSERT INTO T_ROLE_PERMISSION VALUES ('1', '3'); INSERT INTO T_ROLE_PERMISSION VALUES ('2', '1'); INSERT INTO T_ROLE_PERMISSION VALUES ('1', '1'); -- ---------------------------- -- Table structure for T_USER -- ---------------------------- CREATE TABLE T_USER ( ID NUMBER NOT NULL , USERNAME VARCHAR2(20 BYTE) NOT NULL , PASSWD VARCHAR2(128 BYTE) NOT NULL , CREATE_TIME DATE NULL , STATUS CHAR(1 BYTE) NOT NULL ); COMMENT ON COLUMN T_USER.USERNAME IS '用户名'; COMMENT ON COLUMN T_USER.PASSWD IS '密码'; COMMENT ON COLUMN T_USER.CREATE_TIME IS '创建时间'; COMMENT ON COLUMN T_USER.STATUS IS '是否有效 1:有效 0:锁定'; -- ---------------------------- -- Records of T_USER -- ---------------------------- INSERT INTO T_USER VALUES ('2', 'tester', '243e29429b340192700677d48c09d992', TO_DATE('2017-12-11 17:20:21', 'YYYY-MM-DD HH24:MI:SS'), '1'); INSERT INTO T_USER VALUES ('1', 'mrbird', '42ee25d1e43e9f57119a00d0a39e5250', TO_DATE('2017-12-11 10:52:48', 'YYYY-MM-DD HH24:MI:SS'), '1'); -- ---------------------------- -- Table structure for T_USER_ROLE -- ---------------------------- CREATE TABLE T_USER_ROLE ( USER_ID NUMBER(10) NULL , RID NUMBER(10) NULL ); COMMENT ON COLUMN T_USER_ROLE.USER_ID IS '用户id'; COMMENT ON COLUMN T_USER_ROLE.RID IS '角色id'; -- ---------------------------- -- Records of T_USER_ROLE -- ---------------------------- INSERT INTO T_USER_ROLE VALUES ('1', '1'); INSERT INTO T_USER_ROLE VALUES ('2', '2'); ================================================ FILE: 17.Spring-Boot-Shiro-Session/src/main/resources/mapper/UserMapper.xml ================================================ ================================================ FILE: 17.Spring-Boot-Shiro-Session/src/main/resources/mapper/UserPermissionMapper.xml ================================================ ================================================ FILE: 17.Spring-Boot-Shiro-Session/src/main/resources/mapper/UserRoleMapper.xml ================================================ ================================================ FILE: 17.Spring-Boot-Shiro-Session/src/main/resources/static/css/login.css ================================================ .login-page { width: 360px; padding: 8% 0 0; margin: auto; } .form { position: relative; z-index: 1; background: #ffffff; max-width: 360px; margin: 0 auto 100px; padding: 45px; text-align: center; box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.2), 0 5px 5px 0 rgba(0, 0, 0, 0.24); } .form input { outline: 0; background: #f2f2f2; width: 100%; border: 0; margin: 0 0 15px; padding: 15px; box-sizing: border-box; font-size: 14px; } .form button { text-transform: uppercase; outline: 0; background: #4caf50; width: 100%; border: 0; padding: 15px; color: #ffffff; font-size: 14px; -webkit-transition: all 0.3 ease; transition: all 0.3 ease; cursor: pointer; } .form button:hover, .form button:active, .form button:focus { background: #43a047; } .form .message { margin: 15px 0 0; color: #b3b3b3; font-size: 12px; } .form .message a { color: #4caf50; text-decoration: none; } .form .register-form { display: none; } .form p { text-align: left; margin: 0; font-size: 13px; } .form p input { width: auto; margin-right: 10px; } .container { position: relative; z-index: 1; max-width: 300px; margin: 0 auto; } .container:before, .container:after { content: ""; display: block; clear: both; } .container .info { margin: 50px auto; text-align: center; } .container .info h1 { margin: 0 0 15px; padding: 0; font-size: 36px; font-weight: 300; color: #1a1a1a; } .container .info span { color: #4d4d4d; font-size: 12px; } .container .info span a { color: #000000; text-decoration: none; } .container .info span .fa { color: #ef3b3a; } body { background: #76b852; /* fallback for old browsers */ background: -webkit-linear-gradient(right, #76b852, #8dc26f); background: -moz-linear-gradient(right, #76b852, #8dc26f); background: -o-linear-gradient(right, #76b852, #8dc26f); background: linear-gradient(to left, #76b852, #8dc26f); font-family: Lato,"PingFang SC","Microsoft YaHei",sans-serif; } ================================================ FILE: 17.Spring-Boot-Shiro-Session/src/main/resources/static/js/dateFormat.js ================================================ Date.prototype.Format = function (fmt) { var o = { "M+": this.getMonth() + 1, "d+": this.getDate(), "h+": this.getHours(), "m+": this.getMinutes(), "s+": this.getSeconds(), "q+": Math.floor((this.getMonth() + 3) / 3), "S": this.getMilliseconds() }; if (/(y+)/.test(fmt)){ fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "") .substr(4 - RegExp.$1.length)); } for (var k in o){ if (new RegExp("(" + k + ")").test(fmt)){ fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length))); } } return fmt; } ================================================ FILE: 17.Spring-Boot-Shiro-Session/src/main/resources/templates/403.html ================================================ 暂无权限

您没有权限访问该资源!!

返回 ================================================ FILE: 17.Spring-Boot-Shiro-Session/src/main/resources/templates/index.html ================================================ 首页

你好![[${user.userName}]]

你的角色为超级管理员

你的角色为测试账户

在线用户管理 注销 ================================================ FILE: 17.Spring-Boot-Shiro-Session/src/main/resources/templates/login.html ================================================ 登录 ================================================ FILE: 17.Spring-Boot-Shiro-Session/src/main/resources/templates/online.html ================================================ 在线用户管理

在线用户数:

序号 用户名称 登录时间 最后访问时间 主机 状态 操作
返回 ================================================ FILE: 17.Spring-Boot-Shiro-Session/src/main/resources/templates/user.html ================================================ [[${value}]]

[[${value}]]

返回 ================================================ FILE: 18.Spring-Boot-Jackson/pom.xml ================================================ 4.0.0 com.example Spring-Boot-Jackson 0.0.1-SNAPSHOT jar demo Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.9.RELEASE UTF-8 UTF-8 1.7 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test test org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 18.Spring-Boot-Jackson/src/main/java/com/example/DemoApplication.java ================================================ package com.example; import java.io.IOException; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import com.fasterxml.jackson.core.JsonProcessingException; @SpringBootApplication public class DemoApplication { public static void main(String[] args) throws JsonProcessingException, IOException { SpringApplication.run(DemoApplication.class, args); } } ================================================ FILE: 18.Spring-Boot-Jackson/src/main/java/com/example/config/JacksonConfig.java ================================================ package com.example.config; import java.text.SimpleDateFormat; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import com.fasterxml.jackson.databind.ObjectMapper; @Configuration public class JacksonConfig { @Bean public ObjectMapper getObjectMapper(){ ObjectMapper mapper = new ObjectMapper(); mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")); return mapper; } } ================================================ FILE: 18.Spring-Boot-Jackson/src/main/java/com/example/config/UserDeserializer.java ================================================ package com.example.config; import java.io.IOException; import com.example.pojo.User; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.JsonNode; public class UserDeserializer extends JsonDeserializer { @Override public User deserialize(JsonParser parser, DeserializationContext context) throws IOException, JsonProcessingException { JsonNode node = parser.getCodec().readTree(parser); String userName = node.get("user-name").asText(); User user = new User(); user.setUserName(userName); return user; } } ================================================ FILE: 18.Spring-Boot-Jackson/src/main/java/com/example/config/UserSerializer.java ================================================ package com.example.config; import java.io.IOException; import com.example.pojo.User; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; public class UserSerializer extends JsonSerializer { @Override public void serialize(User user, JsonGenerator generator, SerializerProvider provider) throws IOException, JsonProcessingException { generator.writeStartObject(); generator.writeStringField("user-name", user.getUserName()); generator.writeEndObject(); } } ================================================ FILE: 18.Spring-Boot-Jackson/src/main/java/com/example/controller/TestJsonController.java ================================================ package com.example.controller; import java.io.IOException; import java.util.Date; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import com.example.pojo.User; import com.fasterxml.jackson.annotation.JsonView; import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; @Controller public class TestJsonController { @Autowired ObjectMapper mapper; @JsonView(User.AllUserFieldView.class) @RequestMapping("getuser") @ResponseBody public User getUser() { User user = new User(); user.setUserName("mrbird"); user.setAge(26); user.setPassword("123456"); user.setBirthday(new Date()); return user; } @RequestMapping("serialization") @ResponseBody public String serialization() { try { User user = new User(); user.setUserName("mrbird"); user.setBirthday(new Date()); String str = mapper.writeValueAsString(user); return str; } catch (Exception e) { e.printStackTrace(); } return null; } @RequestMapping("readjsonstring") @ResponseBody public String readJsonString() { try { String json = "{\"name\":\"mrbird\",\"age\":26}"; JsonNode node = this.mapper.readTree(json); String name = node.get("name").asText(); int age = node.get("age").asInt(); return name + " " + age; } catch (Exception e) { e.printStackTrace(); } return null; } @RequestMapping("readjsonasobject") @ResponseBody public String readJsonAsObject() { try { String json = "{\"userName\":\"mrbird\"}"; User user = mapper.readValue(json, User.class); String name = user.getUserName(); return name; } catch (Exception e) { e.printStackTrace(); } return null; } @RequestMapping("formatobjecttojsonstring") @ResponseBody public String formatObjectToJsonString() { try { User user = new User(); user.setUserName("mrbird"); user.setAge(26); user.setPassword("123456"); user.setBirthday(new Date()); String jsonStr = mapper.writeValueAsString(user); return jsonStr; } catch (Exception e) { e.printStackTrace(); } return null; } @RequestMapping("updateuser") @ResponseBody public int updateUser(@RequestBody List list) { return list.size(); } @RequestMapping("customize") @ResponseBody public String customize() throws JsonParseException, JsonMappingException, IOException { String jsonStr = "[{\"userName\":\"mrbird\",\"age\":26},{\"userName\":\"scott\",\"age\":27}]"; JavaType type = mapper.getTypeFactory().constructParametricType(List.class, User.class); List list = mapper.readValue(jsonStr, type); String msg = ""; for (User user : list) { msg += user.getUserName(); } return msg; } } ================================================ FILE: 18.Spring-Boot-Jackson/src/main/java/com/example/pojo/User.java ================================================ package com.example.pojo; import java.io.Serializable; import java.util.Date; import com.example.config.UserDeserializer; import com.example.config.UserSerializer; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonView; import com.fasterxml.jackson.databind.PropertyNamingStrategy; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonNaming; import com.fasterxml.jackson.databind.annotation.JsonSerialize; //@JsonIgnoreProperties({ "password", "age" }) //@JsonNaming(PropertyNamingStrategy.LowerCaseWithUnderscoresStrategy.class) //@JsonSerialize(using = UserSerializer.class) //@JsonDeserialize (using = UserDeserializer.class) public class User implements Serializable { private static final long serialVersionUID = 6222176558369919436L; public interface UserNameView { }; public interface AllUserFieldView extends UserNameView { }; @JsonView(UserNameView.class) private String userName; @JsonView(AllUserFieldView.class) private int age; // @JsonIgnore @JsonView(AllUserFieldView.class) private String password; // @JsonProperty("bth") // @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonView(AllUserFieldView.class) private Date birthday; public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public int getAge() { return age; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public void setAge(int age) { this.age = age; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } } ================================================ FILE: 18.Spring-Boot-Jackson/src/main/resources/application.properties ================================================ ================================================ FILE: 18.Spring-Boot-Jackson/src/test/java/com/example/demo/DemoApplicationTests.java ================================================ package com.example.demo; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) @SpringBootTest public class DemoApplicationTests { @Test public void contextLoads() { } } ================================================ FILE: 19.Spring-Boot-Testing/pom.xml ================================================ 4.0.0 demo.springboot Spring-Boot-Testing 0.0.1-SNAPSHOT jar test Demo project for Spring Boot test org.springframework.boot spring-boot-starter-parent 1.5.9.RELEASE UTF-8 UTF-8 1.7 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test test org.mybatis.spring.boot mybatis-spring-boot-starter 1.3.1 tk.mybatis mapper-spring-boot-starter 1.1.5 com.github.pagehelper pagehelper-spring-boot-starter 1.2.3 com.oracle ojdbc6 6.0 com.alibaba druid-spring-boot-starter 1.1.6 org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 19.Spring-Boot-Testing/src/main/java/demo/springboot/test/TestApplication.java ================================================ package demo.springboot.test; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.transaction.annotation.EnableTransactionManagement; @SpringBootApplication @EnableTransactionManagement @MapperScan("demo.springboot.test.mapper") public class TestApplication { public static void main(String[] args) { SpringApplication.run(TestApplication.class, args); } } ================================================ FILE: 19.Spring-Boot-Testing/src/main/java/demo/springboot/test/config/MyMapper.java ================================================ package demo.springboot.test.config; import tk.mybatis.mapper.common.Mapper; import tk.mybatis.mapper.common.MySqlMapper; public interface MyMapper extends Mapper, MySqlMapper { } ================================================ FILE: 19.Spring-Boot-Testing/src/main/java/demo/springboot/test/controller/UserController.java ================================================ package demo.springboot.test.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import demo.springboot.test.domain.User; import demo.springboot.test.service.UserService; @RestController public class UserController { @Autowired UserService userService; @GetMapping("user/{userName}") public User getUserByName(@PathVariable(value = "userName") String userName) { return this.userService.findByName(userName); } @PostMapping("user/save") public void saveUser(@RequestBody User user) { this.userService.saveUser(user); } } ================================================ FILE: 19.Spring-Boot-Testing/src/main/java/demo/springboot/test/domain/User.java ================================================ package demo.springboot.test.domain; import java.util.Date; import javax.persistence.Column; import javax.persistence.Id; import javax.persistence.Table; @Table(name = "T_USER") public class User { @Id @Column(name = "USER_ID") private Long id; @Column(name = "USERNAME") private String username; @Column(name = "PASSWORD") private String passwd; @Column(name = "CRATE_TIME") private Date createTime; @Column(name = "STATUS") private String status; /** * @return ID */ public Long getId() { return id; } /** * @param id */ public void setId(Long id) { this.id = id; } /** * @return USERNAME */ public String getUsername() { return username; } /** * @param username */ public void setUsername(String username) { this.username = username == null ? null : username.trim(); } /** * @return PASSWD */ public String getPasswd() { return passwd; } /** * @param passwd */ public void setPasswd(String passwd) { this.passwd = passwd == null ? null : passwd.trim(); } /** * @return CREATE_TIME */ public Date getCreateTime() { return createTime; } /** * @param createTime */ public void setCreateTime(Date createTime) { this.createTime = createTime; } /** * @return STATUS */ public String getStatus() { return status; } /** * @param status */ public void setStatus(String status) { this.status = status == null ? null : status.trim(); } } ================================================ FILE: 19.Spring-Boot-Testing/src/main/java/demo/springboot/test/mapper/SeqenceMapper.java ================================================ package demo.springboot.test.mapper; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; public interface SeqenceMapper { @Select("select ${seqName}.nextval from dual") Long getSequence(@Param("seqName") String seqName); } ================================================ FILE: 19.Spring-Boot-Testing/src/main/java/demo/springboot/test/mapper/UserMapper.java ================================================ package demo.springboot.test.mapper; import demo.springboot.test.config.MyMapper; import demo.springboot.test.domain.User; public interface UserMapper extends MyMapper { } ================================================ FILE: 19.Spring-Boot-Testing/src/main/java/demo/springboot/test/service/IService.java ================================================ package demo.springboot.test.service; import java.util.List; import org.apache.ibatis.annotations.Param; import org.springframework.stereotype.Service; @Service public interface IService { Long getSequence(@Param("seqName") String seqName); List selectAll(); T selectByKey(Object key); int save(T entity); int delete(Object key); int updateAll(T entity); int updateNotNull(T entity); List selectByExample(Object example); } ================================================ FILE: 19.Spring-Boot-Testing/src/main/java/demo/springboot/test/service/UserService.java ================================================ package demo.springboot.test.service; import demo.springboot.test.domain.User; public interface UserService extends IService{ User findByName(String userName); void saveUser(User user); } ================================================ FILE: 19.Spring-Boot-Testing/src/main/java/demo/springboot/test/service/impl/BaseService.java ================================================ package demo.springboot.test.service.impl; import java.util.List; import org.apache.ibatis.annotations.Param; import org.springframework.beans.factory.annotation.Autowired; import demo.springboot.test.mapper.SeqenceMapper; import demo.springboot.test.service.IService; import tk.mybatis.mapper.common.Mapper; public abstract class BaseService implements IService { @Autowired protected Mapper mapper; @Autowired protected SeqenceMapper seqenceMapper; public Mapper getMapper() { return mapper; } @Override public Long getSequence(@Param("seqName") String seqName){ return seqenceMapper.getSequence(seqName); } @Override public List selectAll() { //说明:查询所有数据 return mapper.selectAll(); } @Override public T selectByKey(Object key) { //说明:根据主键字段进行查询,方法参数必须包含完整的主键属性,查询条件使用等号 return mapper.selectByPrimaryKey(key); } @Override public int save(T entity) { //说明:保存一个实体,null的属性也会保存,不会使用数据库默认值 return mapper.insert(entity); } @Override public int delete(Object key) { //说明:根据主键字段进行删除,方法参数必须包含完整的主键属性 return mapper.deleteByPrimaryKey(key); } @Override public int updateAll(T entity) { //说明:根据主键更新实体全部字段,null值会被更新 return mapper.updateByPrimaryKey(entity); } @Override public int updateNotNull(T entity) { //根据主键更新属性不为null的值 return mapper.updateByPrimaryKeySelective(entity); } @Override public List selectByExample(Object example) { //说明:根据Example条件进行查询 //重点:这个查询支持通过Example类指定查询列,通过selectProperties方法指定查询列 return mapper.selectByExample(example); } } ================================================ FILE: 19.Spring-Boot-Testing/src/main/java/demo/springboot/test/service/impl/UserServiceImpl.java ================================================ package demo.springboot.test.service.impl; import java.util.Date; import java.util.List; import org.springframework.stereotype.Repository; import demo.springboot.test.domain.User; import demo.springboot.test.service.UserService; import tk.mybatis.mapper.entity.Example; @Repository("userService") public class UserServiceImpl extends BaseService implements UserService { @Override public User findByName(String userName) { Example example = new Example(User.class); example.createCriteria().andCondition("username=", userName); List userList = this.selectByExample(example); if (userList.size() != 0) return userList.get(0); else return null; } @Override public void saveUser(User user) { user.setId(this.getSequence("seq_user")); user.setCreateTime(new Date()); this.save(user); } } ================================================ FILE: 19.Spring-Boot-Testing/src/main/resources/application.yml ================================================ server: context-path: /web spring: datasource: druid: # 数据库访问配置, 使用druid数据源 type: com.alibaba.druid.pool.DruidDataSource driver-class-name: oracle.jdbc.driver.OracleDriver url: jdbc:oracle:thin:@localhost:1521:ORCL username: test password: 123456 # 连接池配置 initial-size: 5 min-idle: 5 max-active: 20 # 连接等待超时时间 max-wait: 30000 # 配置检测可以关闭的空闲连接间隔时间 time-between-eviction-runs-millis: 60000 # 配置连接在池中的最小生存时间 min-evictable-idle-time-millis: 300000 validation-query: select '1' from dual test-while-idle: true test-on-borrow: false test-on-return: false # 打开PSCache,并且指定每个连接上PSCache的大小 pool-prepared-statements: true max-open-prepared-statements: 20 max-pool-prepared-statement-per-connection-size: 20 # 配置监控统计拦截的filters, 去掉后监控界面sql无法统计, 'wall'用于防火墙 filters: stat,wall # Spring监控AOP切入点,如x.y.z.service.*,配置多个英文逗号分隔 aop-patterns: demo.springboot.test.servie.* # WebStatFilter配置 web-stat-filter: enabled: true # 添加过滤规则 url-pattern: /* # 忽略过滤的格式 exclusions: '*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*' # StatViewServlet配置 stat-view-servlet: enabled: true # 访问路径为/druid时,跳转到StatViewServlet url-pattern: /druid/* # 是否能够重置数据 reset-enable: false # 需要账号密码才能访问控制台 login-username: druid login-password: druid123 # IP白名单 # allow: 127.0.0.1 # IP黑名单(共同存在时,deny优先于allow) # deny: 192.168.1.218 # 配置StatFilter filter: stat: log-slow-sql: true mybatis: config-location: classpath:config/mybatis-config.xml # type-aliases扫描路径 type-aliases-package: demo.springboot.test.domain # mapper xml实现扫描路径 mapper-locations: classpath:mapper/*.xml property: order: BEFORE #mappers 多个接口时逗号隔开 mapper: mappers: demo.springboot.test.config.MyMapper not-empty: false identity: oracle #pagehelper pagehelper: helperDialect: oracle reasonable: true supportMethodsArguments: true params: count=countSql ================================================ FILE: 19.Spring-Boot-Testing/src/main/resources/config/mybatis-config.xml ================================================ ================================================ FILE: 19.Spring-Boot-Testing/src/main/resources/init.sql ================================================ -- ---------------------------- -- Table structure for T_USER -- ---------------------------- CREATE TABLE T_USER ( ID NUMBER NOT NULL , USERNAME VARCHAR2(20 BYTE) NOT NULL , PASSWD VARCHAR2(128 BYTE) NOT NULL , CREATE_TIME DATE NULL , STATUS CHAR(1 BYTE) NOT NULL ); COMMENT ON COLUMN T_USER.USERNAME IS '用户名'; COMMENT ON COLUMN T_USER.PASSWD IS '密码'; COMMENT ON COLUMN T_USER.CREATE_TIME IS '创建时间'; COMMENT ON COLUMN T_USER.STATUS IS '是否有效 1:有效 0:锁定'; -- ---------------------------- -- Records of T_USER -- ---------------------------- INSERT INTO T_USER VALUES ('2', 'tester', '243e29429b340192700677d48c09d992', TO_DATE('2017-12-11 17:20:21', 'YYYY-MM-DD HH24:MI:SS'), '1'); INSERT INTO T_USER VALUES ('1', 'mrbird', '42ee25d1e43e9f57119a00d0a39e5250', TO_DATE('2017-12-11 10:52:48', 'YYYY-MM-DD HH24:MI:SS'), '1'); create sequence seq_user start with 1 INCREMENT by 1; ================================================ FILE: 19.Spring-Boot-Testing/src/test/java/demo/springboot/test/UserControllerTest.java ================================================ package demo.springboot.test; import javax.servlet.http.Cookie; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.MediaType; import org.springframework.mock.web.MockHttpSession; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.result.MockMvcResultHandlers; import org.springframework.test.web.servlet.result.MockMvcResultMatchers; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.context.WebApplicationContext; import com.fasterxml.jackson.databind.ObjectMapper; import com.jayway.jsonpath.JsonPath; import demo.springboot.test.domain.User; @RunWith(SpringRunner.class) @SpringBootTest public class UserControllerTest { private MockMvc mockMvc; private MockHttpSession session; @Autowired private WebApplicationContext wac; @Autowired ObjectMapper mapper; @Before public void setupMockMvc(){ mockMvc = MockMvcBuilders.webAppContextSetup(wac).build(); session = new MockHttpSession(); User user =new User(); user.setUsername("Dopa"); user.setPasswd("ac3af72d9f95161a502fd326865c2f15"); session.setAttribute("user",user); } @Test @Transactional public void test() throws Exception { // mockMvc.perform( // MockMvcRequestBuilders.get("/user/{userName}", "scott") // .contentType(MediaType.APPLICATION_JSON_UTF8)) // .andExpect(MockMvcResultMatchers.status().isOk()) // .andExpect(MockMvcResultMatchers.jsonPath("$.username").value("scott")) // .andDo(MockMvcResultHandlers.print()); // String jsonStr = "{\"username\":\"Dopa\",\"passwd\":\"ac3af72d9f95161a502fd326865c2f15\",\"status\":\"1\"}"; User user = new User(); user.setUsername("Dopa"); user.setPasswd("ac3af72d9f95161a502fd326865c2f15"); user.setStatus("1"); String userJson = mapper.writeValueAsString(user); // mockMvc.perform(MockMvcRequestBuilders.post("/user/save").content(jsonStr.getBytes())); mockMvc.perform( MockMvcRequestBuilders.post("/user/save") .contentType(MediaType.APPLICATION_JSON_UTF8) .content(userJson.getBytes())) .andExpect(MockMvcResultMatchers.status().isOk()) .andDo(MockMvcResultHandlers.print()); // mockMvc.perform(MockMvcRequestBuilders.get("/hello?name={name}","mrbird")); // mockMvc.perform(MockMvcRequestBuilders.post("/user/{id}", 1)); // mockMvc.perform(MockMvcRequestBuilders.fileUpload("/fileupload").file("file", "文件内容".getBytes("utf-8"))); // mockMvc.perform(MockMvcRequestBuilders.get("/hello").param("message", "hello")); // mockMvc.perform(MockMvcRequestBuilders.get("/hobby/save").param("hobby", "sleep", "eat")); // MultiValueMap params = new LinkedMultiValueMap(); // params.add("name", "mrbird"); // params.add("hobby", "sleep"); // params.add("hobby", "eat"); // mockMvc.perform(MockMvcRequestBuilders.get("/hobby/save").params(params)); // mockMvc.perform(MockMvcRequestBuilders.get("/index").sessionAttr(name, value)); // mockMvc.perform(MockMvcRequestBuilders.get("/index").cookie(new Cookie(name, value))); // mockMvc.perform(MockMvcRequestBuilders.get("/index").contentType(MediaType.APPLICATION_JSON_UTF8)); // mockMvc.perform(MockMvcRequestBuilders.get("/user/{id}", 1).accept(MediaType.APPLICATION_JSON)); // mockMvc.perform(MockMvcRequestBuilders.get("/user/{id}", 1).header(name, values)); // mockMvc.perform(MockMvcRequestBuilders.get("/index")) // .andDo(MockMvcResultHandlers.print()); } } ================================================ FILE: 20.Spring-Boot-Swagger2/pom.xml ================================================ 4.0.0 com.example Spring-Boot-Swagger2 0.0.1-SNAPSHOT jar demo Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.11.RELEASE UTF-8 UTF-8 1.7 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test test io.springfox springfox-swagger2 2.6.1 io.springfox springfox-swagger-ui 2.6.1 org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 20.Spring-Boot-Swagger2/src/main/java/com/example/demo/DemoApplication.java ================================================ package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); System.out.println("complete"); } } ================================================ FILE: 20.Spring-Boot-Swagger2/src/main/java/com/example/demo/config/SwaggerConfig.java ================================================ package com.example.demo.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import springfox.documentation.builders.ApiInfoBuilder; import springfox.documentation.builders.PathSelectors; import springfox.documentation.builders.RequestHandlerSelectors; import springfox.documentation.service.ApiInfo; import springfox.documentation.service.Contact; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spring.web.plugins.Docket; import springfox.documentation.swagger2.annotations.EnableSwagger2; @Configuration @EnableSwagger2 public class SwaggerConfig { @Bean public Docket buildDocket() { return new Docket(DocumentationType.SWAGGER_2) .apiInfo(buildApiInf()) .select() .apis(RequestHandlerSelectors.basePackage("com.example.demo.controller")) .paths(PathSelectors.any()) .build(); } private ApiInfo buildApiInf() { return new ApiInfoBuilder() .title("系统RESTful API文档") .contact(new Contact("mrbird", "https://mrbird.cc", "852252810@qq.com")) .version("1.0") .build(); } } ================================================ FILE: 20.Spring-Boot-Swagger2/src/main/java/com/example/demo/config/WebConfig.java ================================================ package com.example.demo.config; import java.text.SimpleDateFormat; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import com.fasterxml.jackson.databind.ObjectMapper; @Configuration public class WebConfig { @Bean public ObjectMapper getObjectMapper() { ObjectMapper mapper = new ObjectMapper(); mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")); return mapper; } } ================================================ FILE: 20.Spring-Boot-Swagger2/src/main/java/com/example/demo/controller/UserController.java ================================================ package com.example.demo.controller; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import com.example.demo.domain.User; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParams; import io.swagger.annotations.ApiOperation; import springfox.documentation.annotations.ApiIgnore; @Api(value = "用户Controller") @Controller @RequestMapping("user") public class UserController { @ApiIgnore @GetMapping("hello") public @ResponseBody String hello() { return "hello"; } @ApiOperation(value = "获取用户信息", notes = "根据用户id获取用户信息") @ApiImplicitParam(name = "id", value = "用户id", required = true, dataType = "Long", paramType = "path") @GetMapping("/{id}") public @ResponseBody User getUserById(@PathVariable(value = "id") Long id) { User user = new User(); user.setId(id); user.setName("mrbird"); user.setAge(25); return user; } @ApiOperation(value = "获取用户列表", notes = "获取用户列表") @GetMapping("/list") public @ResponseBody List getUserList() { List list = new ArrayList<>(); User user1 = new User(); user1.setId(1l); user1.setName("mrbird"); user1.setAge(25); list.add(user1); User user2 = new User(); user2.setId(2l); user2.setName("scott"); user2.setAge(29); list.add(user2); return list; } @ApiOperation(value = "新增用户", notes = "根据用户实体创建用户") @ApiImplicitParam(name = "user", value = "用户实体", required = true, dataType = "User") @PostMapping("/add") public @ResponseBody Map addUser(@RequestBody User user) { Map map = new HashMap<>(); map.put("result", "success"); return map; } @ApiOperation(value = "删除用户", notes = "根据用户id删除用户") @ApiImplicitParam(name = "id", value = "用户id", required = true, dataType = "Long", paramType = "path") @DeleteMapping("/{id}") public @ResponseBody Map deleteUser(@PathVariable(value = "id") Long id) { Map map = new HashMap<>(); map.put("result", "success"); return map; } @ApiOperation(value = "更新用户", notes = "根据用户id更新用户") @ApiImplicitParams({ @ApiImplicitParam(name = "id", value = "用户id", required = true, dataType = "Long", paramType = "path"), @ApiImplicitParam(name = "user", value = "用户实体", required = true, dataType = "User") }) @PutMapping("/{id}") public @ResponseBody Map updateUser(@PathVariable(value = "id") Long id, @RequestBody User user) { Map map = new HashMap<>(); map.put("result", "success"); return map; } } ================================================ FILE: 20.Spring-Boot-Swagger2/src/main/java/com/example/demo/domain/User.java ================================================ package com.example.demo.domain; import java.io.Serializable; public class User implements Serializable { private static final long serialVersionUID = -2731598327208972274L; private Long id; private String name; private Integer age; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } } ================================================ FILE: 20.Spring-Boot-Swagger2/src/main/resources/application.yml ================================================ ================================================ FILE: 20.Spring-Boot-Swagger2/src/test/java/com/example/demo/DemoApplicationTests.java ================================================ package com.example.demo; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) @SpringBootTest public class DemoApplicationTests { @Test public void contextLoads() { } } ================================================ FILE: 21.Spring-Boot-Actuator/pom.xml ================================================ 4.0.0 com.springboot Spring-Boot-Actuator 0.0.1-SNAPSHOT jar Spring-Boot-Actuator Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.9.RELEASE UTF-8 UTF-8 1.7 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test test org.springframework.boot spring-boot-starter-actuator nexus-aliyun Nexus aliyun http://maven.aliyun.com/nexus/content/groups/public org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 21.Spring-Boot-Actuator/src/main/java/com/springboot/demo/DemoApplication.java ================================================ package com.springboot.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @SpringBootApplication public class DemoApplication { @RequestMapping("/") String index() { return "hello spring boot"; } public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ================================================ FILE: 21.Spring-Boot-Actuator/src/main/resources/application.yml ================================================ server: port: 80 management: security: enabled: false #关掉安全认证 port: 80 context-path: /monitor #actuator的访问路径 endpoints: shutdown: enabled: true beans: id: instances ================================================ FILE: 21.Spring-Boot-Actuator/src/test/java/com/springboot/demo/DemoApplicationTests.java ================================================ package com.springboot.demo; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) @SpringBootTest public class DemoApplicationTests { @Test public void contextLoads() { } } ================================================ FILE: 22.Spring-Boot-Email/pom.xml ================================================ 4.0.0 com.springboot Spring-Boot-Email 0.0.1-SNAPSHOT jar Spring-Boot-Email Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.9.RELEASE UTF-8 UTF-8 1.7 3.0.2.RELEASE 2.0.1 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test test org.springframework.boot spring-boot-starter-mail org.springframework.boot spring-boot-starter-thymeleaf nexus-aliyun Nexus aliyun http://maven.aliyun.com/nexus/content/groups/public org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 22.Spring-Boot-Email/src/main/java/com/springboot/demo/DemoApplication.java ================================================ package com.springboot.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ================================================ FILE: 22.Spring-Boot-Email/src/main/java/com/springboot/demo/controller/EmailController.java ================================================ package com.springboot.demo.controller; import java.io.File; import javax.mail.internet.MimeMessage; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.io.FileSystemResource; import org.springframework.mail.SimpleMailMessage; import org.springframework.mail.javamail.JavaMailSender; import org.springframework.mail.javamail.MimeMessageHelper; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.thymeleaf.TemplateEngine; import org.thymeleaf.context.Context; @RestController @RequestMapping("/email") public class EmailController { @Autowired private JavaMailSender jms; @Value("${spring.mail.username}") private String from; @Autowired private TemplateEngine templateEngine; @RequestMapping("sendSimpleEmail") public String sendSimpleEmail() { try { SimpleMailMessage message = new SimpleMailMessage(); message.setFrom(from); message.setTo("888888@qq.com"); // 接收地址 message.setSubject("一封简单的邮件"); // 标题 message.setText("使用Spring Boot发送简单邮件。"); // 内容 jms.send(message); return "发送成功"; } catch (Exception e) { e.printStackTrace(); return e.getMessage(); } } @RequestMapping("sendHtmlEmail") public String sendHtmlEmail() { MimeMessage message = null; try { message = jms.createMimeMessage(); MimeMessageHelper helper = new MimeMessageHelper(message, true); helper.setFrom(from); helper.setTo("888888@qq.com"); // 接收地址 helper.setSubject("一封HTML格式的邮件"); // 标题 // 带HTML格式的内容 StringBuffer sb = new StringBuffer("

使用Spring Boot发送HTML格式邮件。

"); helper.setText(sb.toString(), true); jms.send(message); return "发送成功"; } catch (Exception e) { e.printStackTrace(); return e.getMessage(); } } @RequestMapping("sendAttachmentsMail") public String sendAttachmentsMail() { MimeMessage message = null; try { message = jms.createMimeMessage(); MimeMessageHelper helper = new MimeMessageHelper(message, true); helper.setFrom(from); helper.setTo("888888@qq.com"); // 接收地址 helper.setSubject("一封带附件的邮件"); // 标题 helper.setText("详情参见附件内容!"); // 内容 // 传入附件 FileSystemResource file = new FileSystemResource(new File("src/main/resources/static/file/项目文档.docx")); helper.addAttachment("项目文档.docx", file); jms.send(message); return "发送成功"; } catch (Exception e) { e.printStackTrace(); return e.getMessage(); } } @RequestMapping("sendInlineMail") public String sendInlineMail() { MimeMessage message = null; try { message = jms.createMimeMessage(); MimeMessageHelper helper = new MimeMessageHelper(message, true); helper.setFrom(from); helper.setTo("888888@qq.com"); // 接收地址 helper.setSubject("一封带静态资源的邮件"); // 标题 helper.setText("博客图:", true); // 内容 // 传入附件 FileSystemResource file = new FileSystemResource(new File("src/main/resources/static/img/sunshine.png")); helper.addInline("img", file); jms.send(message); return "发送成功"; } catch (Exception e) { e.printStackTrace(); return e.getMessage(); } } @RequestMapping("sendTemplateEmail") public String sendTemplateEmail(String code) { MimeMessage message = null; try { message = jms.createMimeMessage(); MimeMessageHelper helper = new MimeMessageHelper(message, true); helper.setFrom(from); helper.setTo("888888@qq.com"); // 接收地址 helper.setSubject("邮件摸板测试"); // 标题 // 处理邮件模板 Context context = new Context(); context.setVariable("code", code); String template = templateEngine.process("emailTemplate", context); helper.setText(template, true); jms.send(message); return "发送成功"; } catch (Exception e) { e.printStackTrace(); return e.getMessage(); } } } ================================================ FILE: 22.Spring-Boot-Email/src/main/resources/application.yml ================================================ server: port: 80 spring: mail: host: smtp.163.com username: xxxx@163.com password: xxxx properties: mail: smtp: auth: true starttls: enable: true required: true ================================================ FILE: 22.Spring-Boot-Email/src/main/resources/templates/emailTemplate.html ================================================ 模板 您好,您的验证码为,请在两分钟内使用完成操作。 ================================================ FILE: 22.Spring-Boot-Email/src/test/java/com/springboot/demo/DemoApplicationTests.java ================================================ package com.springboot.demo; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) @SpringBootTest public class DemoApplicationTests { @Test public void contextLoads() { } } ================================================ FILE: 23.Spring-Boot-Admin/Spring Boot Admin Client/pom.xml ================================================ 4.0.0 com.example Spring-Boot-admin-Client 0.0.1-SNAPSHOT jar demo Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.9.RELEASE UTF-8 UTF-8 1.7 org.springframework.boot spring-boot-starter org.springframework.boot spring-boot-starter-test test de.codecentric spring-boot-admin-starter-client 1.5.7 nexus-aliyun Nexus aliyun http://maven.aliyun.com/nexus/content/groups/public org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 23.Spring-Boot-Admin/Spring Boot Admin Client/src/main/java/com/example/demo/DemoApplication.java ================================================ package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ================================================ FILE: 23.Spring-Boot-Admin/Spring Boot Admin Client/src/main/resources/application.yml ================================================ management: security: enabled: false server: port: 8081 spring: boot: admin: url: http://localhost:8080/admin-server info: app: name: "@project.name@" description: "@project.description@" version: "@project.version@" spring-boot-version: "@project.parent.version@" ================================================ FILE: 23.Spring-Boot-Admin/Spring Boot Admin Client/src/test/java/com/example/demo/DemoApplicationTests.java ================================================ package com.example.demo; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) @SpringBootTest public class DemoApplicationTests { @Test public void contextLoads() { } } ================================================ FILE: 23.Spring-Boot-Admin/Spring Boot Admin Server/pom.xml ================================================ 4.0.0 com.example Spring-Boot-Admin-Server 0.0.1-SNAPSHOT jar Sprign Boot Admin Server Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.9.RELEASE UTF-8 UTF-8 1.7 org.springframework.boot spring-boot-starter org.springframework.boot spring-boot-starter-test test de.codecentric spring-boot-admin-server 1.5.7 de.codecentric spring-boot-admin-server-ui 1.5.7 org.springframework.boot spring-boot-starter-mail nexus-aliyun Nexus aliyun http://maven.aliyun.com/nexus/content/groups/public org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 23.Spring-Boot-Admin/Spring Boot Admin Server/src/main/java/com/example/demo/DemoApplication.java ================================================ package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.SpringBootApplication; import de.codecentric.boot.admin.config.EnableAdminServer; @SpringBootApplication @EnableAutoConfiguration @EnableAdminServer public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ================================================ FILE: 23.Spring-Boot-Admin/Spring Boot Admin Server/src/main/resources/application.yml ================================================ server: port: 8080 context-path: /admin-server spring: mail: host: smtp.163.com username: xxx@163.com password: xxx properties: mail: smtp: auth: true starttls: enable: true required: true boot: admin: notify: mail: from: xxx@163.com to: xxx@qq.com ================================================ FILE: 23.Spring-Boot-Admin/Spring Boot Admin Server/src/test/java/com/example/demo/DemoApplicationTests.java ================================================ package com.example.demo; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) @SpringBootTest public class DemoApplicationTests { @Test public void contextLoads() { } } ================================================ FILE: 24.Spring-Boot-Devtools/pom.xml ================================================ 4.0.0 com.springboot Spring-Boot-Devtools 0.0.1-SNAPSHOT jar Spring-Boot-Devtools Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.9.RELEASE UTF-8 UTF-8 1.7 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test test org.springframework.boot spring-boot-devtools true nexus-aliyun Nexus aliyun http://maven.aliyun.com/nexus/content/groups/public org.springframework.boot spring-boot-maven-plugin true ================================================ FILE: 24.Spring-Boot-Devtools/src/main/java/com/springboot/demo/DemoApplication.java ================================================ package com.springboot.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @SpringBootApplication public class DemoApplication { @RequestMapping("/") String index() { return "hello world"; } public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ================================================ FILE: 24.Spring-Boot-Devtools/src/main/resources/application.yml ================================================ ================================================ FILE: 24.Spring-Boot-Devtools/src/test/java/com/springboot/demo/DemoApplicationTests.java ================================================ package com.springboot.demo; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) @SpringBootTest public class DemoApplicationTests { @Test public void contextLoads() { } } ================================================ FILE: 25.Spring-Boot-Exception/pom.xml ================================================ 4.0.0 com.springboot Spring-Boot-Exception 0.0.1-SNAPSHOT jar Spring-Boot-Exception Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.14.RELEASE UTF-8 UTF-8 1.8 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test test org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 25.Spring-Boot-Exception/src/main/java/cc/mrbird/Application.java ================================================ package cc.mrbird; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } ================================================ FILE: 25.Spring-Boot-Exception/src/main/java/cc/mrbird/controller/UserController.java ================================================ package cc.mrbird.controller; import cc.mrbird.exception.UserNotExistException; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("user") public class UserController { @GetMapping("/{id:\\d+}") public void get(@PathVariable String id) { throw new UserNotExistException(id); } } ================================================ FILE: 25.Spring-Boot-Exception/src/main/java/cc/mrbird/exception/UserNotExistException.java ================================================ package cc.mrbird.exception; public class UserNotExistException extends RuntimeException{ private static final long serialVersionUID = -1574716826948451793L; private String id; public UserNotExistException(String id){ super("user not exist"); this.id = id; } public String getId() { return id; } public void setId(String id) { this.id = id; } } ================================================ FILE: 25.Spring-Boot-Exception/src/main/java/cc/mrbird/handler/ControllerExceptionHandler.java ================================================ package cc.mrbird.handler; import cc.mrbird.exception.UserNotExistException; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseStatus; import java.util.HashMap; import java.util.Map; @ControllerAdvice public class ControllerExceptionHandler { @ExceptionHandler(UserNotExistException.class) @ResponseBody @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public Map handleUserNotExistsException(UserNotExistException e) { Map map = new HashMap<>(); map.put("id", e.getId()); map.put("message", e.getMessage()); return map; } } ================================================ FILE: 25.Spring-Boot-Exception/src/main/resources/application.properties ================================================ ================================================ FILE: 25.Spring-Boot-Exception/src/main/resources/resources/error/500.html ================================================ 500 系统内部异常 ================================================ FILE: 25.Spring-Boot-Exception/src/test/java/cc/mrbird/cc/mrbird/demo/ApplicationTests.java ================================================ package cc.mrbird.cc.mrbird.demo; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) @SpringBootTest public class ApplicationTests { @Test public void contextLoads() { } } ================================================ FILE: 26.Spring-Boot-Filter-Interceptor/pom.xml ================================================ 4.0.0 com.springboot Spring-Boot-Filter-Interceptor 0.0.1-SNAPSHOT jar Spring-Boot-Filter-Interceptor Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.14.RELEASE UTF-8 UTF-8 1.8 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test test org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 26.Spring-Boot-Filter-Interceptor/src/main/java/cc/mrbird/Application.java ================================================ package cc.mrbird; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } ================================================ FILE: 26.Spring-Boot-Filter-Interceptor/src/main/java/cc/mrbird/config/WebConfig.java ================================================ package cc.mrbird.config; import cc.mrbird.filter.TimeFilter; import cc.mrbird.interceptor.TimeInterceptor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; import java.util.ArrayList; import java.util.List; @Configuration public class WebConfig extends WebMvcConfigurerAdapter { @Bean public FilterRegistrationBean timeFilter() { FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(); TimeFilter timeFilter = new TimeFilter(); filterRegistrationBean.setFilter(timeFilter); List urlList = new ArrayList<>(); urlList.add("/*"); filterRegistrationBean.setUrlPatterns(urlList); return filterRegistrationBean; } @Autowired private TimeInterceptor timeInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(timeInterceptor); } } ================================================ FILE: 26.Spring-Boot-Filter-Interceptor/src/main/java/cc/mrbird/controller/UserController.java ================================================ package cc.mrbird.controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("user") public class UserController { @GetMapping("/{id:\\d+}") public void get(@PathVariable String id) { System.out.println(id); // throw new RuntimeException("user not exist"); } } ================================================ FILE: 26.Spring-Boot-Filter-Interceptor/src/main/java/cc/mrbird/filter/TimeFilter.java ================================================ package cc.mrbird.filter; import org.springframework.stereotype.Component; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import java.io.IOException; import java.util.Date; // @Component // @WebFilter(urlPatterns = {"/*"}) public class TimeFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("过滤器初始化"); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("开始执行过滤器"); Long start = new Date().getTime(); filterChain.doFilter(servletRequest, servletResponse); System.out.println("【过滤器】耗时 " + (new Date().getTime() - start)); System.out.println("结束执行过滤器"); } @Override public void destroy() { System.out.println("过滤器销毁"); } } ================================================ FILE: 26.Spring-Boot-Filter-Interceptor/src/main/java/cc/mrbird/interceptor/TimeInterceptor.java ================================================ package cc.mrbird.interceptor; import org.springframework.stereotype.Component; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.Date; @Component public class TimeInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception { System.out.println("处理拦截之前"); httpServletRequest.setAttribute("startTime", new Date().getTime()); System.out.println(((HandlerMethod) o).getBean().getClass().getName()); System.out.println(((HandlerMethod) o).getMethod().getName()); return true; } @Override public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception { System.out.println("开始处理拦截"); Long start = (Long) httpServletRequest.getAttribute("startTime"); System.out.println("【拦截器】耗时 " + (new Date().getTime() - start)); } @Override public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception { System.out.println("处理拦截之后"); Long start = (Long) httpServletRequest.getAttribute("startTime"); System.out.println("【拦截器】耗时 " + (new Date().getTime() - start)); System.out.println("异常信息 " + e); } } ================================================ FILE: 26.Spring-Boot-Filter-Interceptor/src/main/resources/application.properties ================================================ ================================================ FILE: 26.Spring-Boot-Filter-Interceptor/src/main/resources/resources/error/500.html ================================================ 500 系统内部异常 ================================================ FILE: 26.Spring-Boot-Filter-Interceptor/src/test/java/cc/mrbird/cc/mrbird/demo/ApplicationTests.java ================================================ package cc.mrbird.cc.mrbird.demo; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) @SpringBootTest public class ApplicationTests { @Test public void contextLoads() { } } ================================================ FILE: 27.Spring-Boot-Mapper-PageHelper/pom.xml ================================================ 4.0.0 com.springboot Spring-Boot-Mapper-PageHelper 0.0.1-SNAPSHOT jar Spring-Boot-Mapper-PageHelper Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.9.RELEASE UTF-8 UTF-8 1.7 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test org.mybatis.spring.boot mybatis-spring-boot-starter 1.3.1 tk.mybatis mapper-spring-boot-starter 1.1.5 com.github.pagehelper pagehelper-spring-boot-starter 1.2.3 com.oracle ojdbc6 6.0 com.alibaba druid-spring-boot-starter 1.1.6 org.springframework.boot spring-boot-maven-plugin org.mybatis.generator mybatis-generator-maven-plugin 1.3.5 com.oracle ojdbc6 6.0 tk.mybatis mapper 3.4.0 Generate MyBatis Artifacts package generate true true src/main/resources/mybatis-generator.xml ================================================ FILE: 27.Spring-Boot-Mapper-PageHelper/src/main/java/com/springboot/Application.java ================================================ package com.springboot; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication @MapperScan("com.springboot.mapper") public class Application { public static void main(String[] args) { SpringApplication.run(Application.class,args); } } ================================================ FILE: 27.Spring-Boot-Mapper-PageHelper/src/main/java/com/springboot/ApplicationTest.java ================================================ package com.springboot; import java.util.Date; import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import com.springboot.bean.User; import com.springboot.service.UserService; import tk.mybatis.mapper.entity.Example; @RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest(classes = Application.class) public class ApplicationTest { @Autowired private UserService userService; @Test public void test() throws Exception { // User user = new User(); // user.setId(userService.getSequence("seq_user")); // user.setUsername("scott"); // user.setPasswd("ac089b11709f9b9e9980e7c497268dfa"); // user.setCreateTime(new Date()); // user.setStatus("0"); // this.userService.save(user); // Example example = new Example(User.class); // example.createCriteria().andCondition("username like '%i%'"); // example.setOrderByClause("id desc"); // List userList = this.userService.selectByExample(example); // for (User u : userList) { // System.out.println(u.getUsername()); // } // // List all = this.userService.selectAll(); // for (User u : all) { // System.out.println(u.getUsername()); // } // // User user = new User(); // user.setId(1l); // user = this.userService.selectByKey(user); // System.out.println(user.getUsername()); // // user.setId(4l); // this.userService.delete(user); PageHelper.startPage(2, 2); List list = userService.selectAll(); PageInfo pageInfo = new PageInfo(list); List result = pageInfo.getList(); for (User u : result) { System.out.println(u.getUsername()); } } } ================================================ FILE: 27.Spring-Boot-Mapper-PageHelper/src/main/java/com/springboot/bean/User.java ================================================ package com.springboot.bean; import java.util.Date; import javax.persistence.Column; import javax.persistence.Id; import javax.persistence.Table; @Table(name = "T_USER") public class User { @Id @Column(name = "ID") private Long id; @Column(name = "USERNAME") private String username; @Column(name = "PASSWD") private String passwd; @Column(name = "CREATE_TIME") private Date createTime; @Column(name = "STATUS") private String status; /** * @return ID */ public Long getId() { return id; } /** * @param id */ public void setId(Long id) { this.id = id; } /** * @return USERNAME */ public String getUsername() { return username; } /** * @param username */ public void setUsername(String username) { this.username = username == null ? null : username.trim(); } /** * @return PASSWD */ public String getPasswd() { return passwd; } /** * @param passwd */ public void setPasswd(String passwd) { this.passwd = passwd == null ? null : passwd.trim(); } /** * @return CREATE_TIME */ public Date getCreateTime() { return createTime; } /** * @param createTime */ public void setCreateTime(Date createTime) { this.createTime = createTime; } /** * @return STATUS */ public String getStatus() { return status; } /** * @param status */ public void setStatus(String status) { this.status = status == null ? null : status.trim(); } } ================================================ FILE: 27.Spring-Boot-Mapper-PageHelper/src/main/java/com/springboot/config/MyMapper.java ================================================ package com.springboot.config; import tk.mybatis.mapper.common.Mapper; import tk.mybatis.mapper.common.MySqlMapper; public interface MyMapper extends Mapper, MySqlMapper { } ================================================ FILE: 27.Spring-Boot-Mapper-PageHelper/src/main/java/com/springboot/mapper/SeqenceMapper.java ================================================ package com.springboot.mapper; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; public interface SeqenceMapper { @Select("select ${seqName}.nextval from dual") Long getSequence(@Param("seqName") String seqName); } ================================================ FILE: 27.Spring-Boot-Mapper-PageHelper/src/main/java/com/springboot/mapper/UserMapper.java ================================================ package com.springboot.mapper; import com.springboot.bean.User; import com.springboot.config.MyMapper; public interface UserMapper extends MyMapper { } ================================================ FILE: 27.Spring-Boot-Mapper-PageHelper/src/main/java/com/springboot/service/IService.java ================================================ package com.springboot.service; import java.util.List; import org.apache.ibatis.annotations.Param; import org.springframework.stereotype.Service; @Service public interface IService { Long getSequence(@Param("seqName") String seqName); List selectAll(); T selectByKey(Object key); int save(T entity); int delete(Object key); int updateAll(T entity); int updateNotNull(T entity); List selectByExample(Object example); } ================================================ FILE: 27.Spring-Boot-Mapper-PageHelper/src/main/java/com/springboot/service/UserService.java ================================================ package com.springboot.service; import com.springboot.bean.User; public interface UserService extends IService{ } ================================================ FILE: 27.Spring-Boot-Mapper-PageHelper/src/main/java/com/springboot/service/impl/BaseService.java ================================================ package com.springboot.service.impl; import java.util.List; import org.apache.ibatis.annotations.Param; import org.springframework.beans.factory.annotation.Autowired; import com.springboot.mapper.SeqenceMapper; import com.springboot.service.IService; import tk.mybatis.mapper.common.Mapper; public abstract class BaseService implements IService { @Autowired protected Mapper mapper; @Autowired protected SeqenceMapper seqenceMapper; public Mapper getMapper() { return mapper; } @Override public Long getSequence(@Param("seqName") String seqName){ return seqenceMapper.getSequence(seqName); } @Override public List selectAll() { //说明:查询所有数据 return mapper.selectAll(); } @Override public T selectByKey(Object key) { //说明:根据主键字段进行查询,方法参数必须包含完整的主键属性,查询条件使用等号 return mapper.selectByPrimaryKey(key); } @Override public int save(T entity) { //说明:保存一个实体,null的属性也会保存,不会使用数据库默认值 return mapper.insert(entity); } @Override public int delete(Object key) { //说明:根据主键字段进行删除,方法参数必须包含完整的主键属性 return mapper.deleteByPrimaryKey(key); } @Override public int updateAll(T entity) { //说明:根据主键更新实体全部字段,null值会被更新 return mapper.updateByPrimaryKey(entity); } @Override public int updateNotNull(T entity) { //根据主键更新属性不为null的值 return mapper.updateByPrimaryKeySelective(entity); } @Override public List selectByExample(Object example) { //说明:根据Example条件进行查询 //重点:这个查询支持通过Example类指定查询列,通过selectProperties方法指定查询列 return mapper.selectByExample(example); } } ================================================ FILE: 27.Spring-Boot-Mapper-PageHelper/src/main/java/com/springboot/service/impl/UserServiceImpl.java ================================================ package com.springboot.service.impl; import org.springframework.stereotype.Repository; import com.springboot.bean.User; import com.springboot.service.UserService; @Repository("userService") public class UserServiceImpl extends BaseService implements UserService{ } ================================================ FILE: 27.Spring-Boot-Mapper-PageHelper/src/main/resources/application.yml ================================================ server: context-path: /web spring: datasource: druid: # 数据库访问配置, 使用druid数据源 type: com.alibaba.druid.pool.DruidDataSource driver-class-name: oracle.jdbc.driver.OracleDriver url: jdbc:oracle:thin:@localhost:1521:ORCL username: scott password: 6742530 # 连接池配置 initial-size: 5 min-idle: 5 max-active: 20 # 连接等待超时时间 max-wait: 30000 # 配置检测可以关闭的空闲连接间隔时间 time-between-eviction-runs-millis: 60000 # 配置连接在池中的最小生存时间 min-evictable-idle-time-millis: 300000 validation-query: select '1' from dual test-while-idle: true test-on-borrow: false test-on-return: false # 打开PSCache,并且指定每个连接上PSCache的大小 pool-prepared-statements: true max-open-prepared-statements: 20 max-pool-prepared-statement-per-connection-size: 20 # 配置监控统计拦截的filters, 去掉后监控界面sql无法统计, 'wall'用于防火墙 filters: stat,wall # Spring监控AOP切入点,如x.y.z.service.*,配置多个英文逗号分隔 aop-patterns: com.springboot.servie.* # WebStatFilter配置 web-stat-filter: enabled: true # 添加过滤规则 url-pattern: /* # 忽略过滤的格式 exclusions: '*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*' # StatViewServlet配置 stat-view-servlet: enabled: true # 访问路径为/druid时,跳转到StatViewServlet url-pattern: /druid/* # 是否能够重置数据 reset-enable: false # 需要账号密码才能访问控制台 login-username: druid login-password: druid123 # IP白名单 # allow: 127.0.0.1 # IP黑名单(共同存在时,deny优先于allow) # deny: 192.168.1.218 # 配置StatFilter filter: stat: log-slow-sql: true mybatis: # type-aliases扫描路径 type-aliases-package: com.springboot.bean # mapper xml实现扫描路径 mapper-locations: classpath:mapper/*.xml property: order: BEFORE #mappers 多个接口时逗号隔开 mapper: mappers: com.springboot.config.MyMapper not-empty: false identity: oracle #pagehelper pagehelper: helperDialect: oracle reasonable: true supportMethodsArguments: true params: count=countSql logging: level: com: springboot: mapper: debug ================================================ FILE: 27.Spring-Boot-Mapper-PageHelper/src/main/resources/mapper/UserMapper.xml ================================================ ================================================ FILE: 27.Spring-Boot-Mapper-PageHelper/src/main/resources/mybatis-generator.xml ================================================
================================================ FILE: 28.Spring-Cloud-Eureka-Server-Discovery/Eureka-Client/pom.xml ================================================ 4.0.0 com.example Eureka-Client 0.0.1-SNAPSHOT jar Eureka-Client Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.13.RELEASE UTF-8 UTF-8 1.8 org.springframework.cloud spring-cloud-dependencies Edgware.SR3 pom import org.springframework.cloud spring-cloud-starter-eureka org.springframework.boot spring-boot-starter org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 28.Spring-Cloud-Eureka-Server-Discovery/Eureka-Client/src/main/java/com/example/demo/DemoApplication.java ================================================ package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; @EnableDiscoveryClient @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ================================================ FILE: 28.Spring-Cloud-Eureka-Server-Discovery/Eureka-Client/src/main/java/com/example/demo/controller/TestController.java ================================================ package com.example.demo.controller; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class TestController { private Logger log = LoggerFactory.getLogger(this.getClass()); @Autowired private DiscoveryClient client; @GetMapping("/info") public String info() { @SuppressWarnings("deprecation") ServiceInstance instance = client.getLocalServiceInstance(); String info = "host:" + instance.getHost() + ",service_id:" + instance.getServiceId(); log.info(info); return info; } @GetMapping("/hello") public String hello() { return "hello world"; } } ================================================ FILE: 28.Spring-Cloud-Eureka-Server-Discovery/Eureka-Client/src/main/resources/application.yml ================================================ server: port: 8082 spring: application: name: Server-Provider eureka: client: register-with-eureka: true fetch-registry: true serviceUrl: defaultZone: http://mrbird:123456@peer1:8080/eureka/,http://mrbird:123456@peer2:8081/eureka/ ================================================ FILE: 28.Spring-Cloud-Eureka-Server-Discovery/Eureka-Service/pom.xml ================================================ 4.0.0 com.example Eureka-Service 0.0.1-SNAPSHOT jar Eureka-Service Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.13.RELEASE UTF-8 UTF-8 1.8 org.springframework.cloud spring-cloud-dependencies Edgware.SR3 pom import org.springframework.cloud spring-cloud-starter-eureka-server org.springframework.boot spring-boot-starter-security nexus-aliyun Nexus aliyun http://maven.aliyun.com/nexus/content/groups/public org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 28.Spring-Cloud-Eureka-Server-Discovery/Eureka-Service/src/main/java/com/example/demo/DemoApplication.java ================================================ package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @EnableEurekaServer @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ================================================ FILE: 28.Spring-Cloud-Eureka-Server-Discovery/Eureka-Service/src/main/resources/application-peer1.yml ================================================ server: port: 8080 spring: application: name: Eureka-Server eureka: instance: hostname: peer1 client: serviceUrl: defaultZone: http://mrbird:123456@peer2:8081/eureka/ server: enable-self-preservation: false ================================================ FILE: 28.Spring-Cloud-Eureka-Server-Discovery/Eureka-Service/src/main/resources/application-peer2.yml ================================================ server: port: 8081 spring: application: name: Eureka-Server eureka: instance: hostname: peer2 client: serviceUrl: defaultZone: http://mrbird:123456@peer1:8080/eureka/ server: enable-self-preservation: false ================================================ FILE: 28.Spring-Cloud-Eureka-Server-Discovery/Eureka-Service/src/main/resources/application.yml ================================================ spring: profiles: active: peer1 security: basic: enabled: true user: name: mrbird password: 123456 ================================================ FILE: 28.Spring-Cloud-Eureka-Server-Discovery/Server-Consumer/pom.xml ================================================ 4.0.0 com.example Server-Consumer 0.0.1-SNAPSHOT jar Server-Consumer Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.13.RELEASE UTF-8 UTF-8 1.8 org.springframework.cloud spring-cloud-dependencies Edgware.SR3 pom import org.springframework.cloud spring-cloud-starter-eureka org.springframework.boot spring-boot-starter org.springframework.cloud spring-cloud-starter-ribbon org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 28.Spring-Cloud-Eureka-Server-Discovery/Server-Consumer/src/main/java/com/example/demo/DemoApplication.java ================================================ package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; @EnableDiscoveryClient @SpringBootApplication public class DemoApplication { @Bean @LoadBalanced RestTemplate restTemplate() { return new RestTemplate(); } public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ================================================ FILE: 28.Spring-Cloud-Eureka-Server-Discovery/Server-Consumer/src/main/java/com/example/demo/controller/TestController.java ================================================ package com.example.demo.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; @RestController public class TestController { @Autowired private RestTemplate restTemplate; @GetMapping("/info") public String getInfo() { return this.restTemplate.getForEntity("http://Server-Provider/info", String.class).getBody(); } } ================================================ FILE: 28.Spring-Cloud-Eureka-Server-Discovery/Server-Consumer/src/main/resources/application.yml ================================================ server: port: 9000 spring: application: name: Server-Consumer eureka: client: serviceUrl: defaultZone: http://mrbird:123456@peer1:8080/eureka/,http://mrbird:123456@peer2:8081/eureka/ ================================================ FILE: 29.Spring-Cloud-Ribbon-LoadBalance/Eureka-Client/pom.xml ================================================ 4.0.0 com.example Eureka-Client 0.0.1-SNAPSHOT jar Eureka-Client Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.13.RELEASE UTF-8 UTF-8 1.8 org.springframework.cloud spring-cloud-dependencies Edgware.SR3 pom import org.springframework.cloud spring-cloud-starter-eureka org.springframework.boot spring-boot-starter org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 29.Spring-Cloud-Ribbon-LoadBalance/Eureka-Client/src/main/java/com/example/demo/DemoApplication.java ================================================ package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; @EnableDiscoveryClient @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ================================================ FILE: 29.Spring-Cloud-Ribbon-LoadBalance/Eureka-Client/src/main/java/com/example/demo/controller/TestController.java ================================================ package com.example.demo.controller; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class TestController { private Logger log = LoggerFactory.getLogger(this.getClass()); @Autowired private DiscoveryClient client; @GetMapping("/info") public String info() { @SuppressWarnings("deprecation") ServiceInstance instance = client.getLocalServiceInstance(); String info = "host:" + instance.getHost() + ",service_id:" + instance.getServiceId(); log.info(info); return info; } @GetMapping("/hello") public String hello() { return "hello world"; } } ================================================ FILE: 29.Spring-Cloud-Ribbon-LoadBalance/Eureka-Client/src/main/java/com/example/demo/controller/UserController.java ================================================ package com.example.demo.controller; import com.example.demo.domain.User; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.*; import java.util.ArrayList; import java.util.List; @RestController @RequestMapping("user") public class UserController { private Logger log = LoggerFactory.getLogger(this.getClass()); @GetMapping("/{id:\\d+}") public User get(@PathVariable Long id) { log.info("获取用户id为 " + id + "的信息"); return new User(id, "mrbird", "123456"); } @GetMapping public List get() { List list = new ArrayList<>(); list.add(new User(1L, "mrbird", "123456")); list.add(new User(2L, "scott", "123456")); log.info("获取用户信息 " + list); return list; } @PostMapping public void add(@RequestBody User user) { log.info("新增用户成功 " + user); } @PutMapping public void update(@RequestBody User user) { log.info("更新用户成功 " + user); } @DeleteMapping("/{id:\\d+}") public void delete(@PathVariable Long id) { log.info("删除用户成功 " + id); } } ================================================ FILE: 29.Spring-Cloud-Ribbon-LoadBalance/Eureka-Client/src/main/java/com/example/demo/domain/User.java ================================================ package com.example.demo.domain; import java.io.Serializable; public class User implements Serializable { private static final long serialVersionUID = 1339434510787399891L; private Long id; private String username; private String password; public User() { } public User(Long id, String username, String password) { this.id = id; this.username = username; this.password = password; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", password='" + password + '\'' + '}'; } } ================================================ FILE: 29.Spring-Cloud-Ribbon-LoadBalance/Eureka-Client/src/main/resources/application.yml ================================================ server: port: 8082 spring: application: name: Server-Provider eureka: client: register-with-eureka: true fetch-registry: true serviceUrl: defaultZone: http://mrbird:123456@peer1:8080/eureka/,http://mrbird:123456@peer2:8081/eureka/ ================================================ FILE: 29.Spring-Cloud-Ribbon-LoadBalance/Eureka-Service/pom.xml ================================================ 4.0.0 com.example Eureka-Service 0.0.1-SNAPSHOT jar Eureka-Service Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.13.RELEASE UTF-8 UTF-8 1.8 org.springframework.cloud spring-cloud-dependencies Edgware.SR3 pom import org.springframework.cloud spring-cloud-starter-eureka-server org.springframework.boot spring-boot-starter-security nexus-aliyun Nexus aliyun http://maven.aliyun.com/nexus/content/groups/public org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 29.Spring-Cloud-Ribbon-LoadBalance/Eureka-Service/src/main/java/com/example/demo/DemoApplication.java ================================================ package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @EnableEurekaServer @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ================================================ FILE: 29.Spring-Cloud-Ribbon-LoadBalance/Eureka-Service/src/main/resources/application-peer1.yml ================================================ server: port: 8080 spring: application: name: Eureka-Server eureka: instance: hostname: peer1 client: serviceUrl: defaultZone: http://mrbird:123456@peer2:8081/eureka/ server: enable-self-preservation: false ================================================ FILE: 29.Spring-Cloud-Ribbon-LoadBalance/Eureka-Service/src/main/resources/application-peer2.yml ================================================ server: port: 8081 spring: application: name: Eureka-Server eureka: instance: hostname: peer2 client: serviceUrl: defaultZone: http://mrbird:123456@peer1:8080/eureka/ server: enable-self-preservation: false ================================================ FILE: 29.Spring-Cloud-Ribbon-LoadBalance/Eureka-Service/src/main/resources/application.yml ================================================ security: basic: enabled: true user: name: mrbird password: 123456 spring: profiles: active: peer1 ================================================ FILE: 29.Spring-Cloud-Ribbon-LoadBalance/Ribbon-Consumer/pom.xml ================================================ 4.0.0 com.example Ribbon-Consumer 0.0.1-SNAPSHOT jar Ribbon-Consumer Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.13.RELEASE UTF-8 UTF-8 1.8 org.springframework.cloud spring-cloud-dependencies Edgware.SR3 pom import org.springframework.cloud spring-cloud-starter-eureka org.springframework.boot spring-boot-starter org.springframework.cloud spring-cloud-starter-ribbon org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 29.Spring-Cloud-Ribbon-LoadBalance/Ribbon-Consumer/src/main/java/com/example/demo/DemoApplication.java ================================================ package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; @EnableDiscoveryClient @SpringBootApplication public class DemoApplication { @Bean @LoadBalanced RestTemplate restTemplate() { return new RestTemplate(); } public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ================================================ FILE: 29.Spring-Cloud-Ribbon-LoadBalance/Ribbon-Consumer/src/main/java/com/example/demo/controller/TestController.java ================================================ package com.example.demo.controller; import com.example.demo.domain.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; import org.springframework.web.util.UriComponentsBuilder; import java.net.URI; import java.util.HashMap; import java.util.List; import java.util.Map; @RestController public class TestController { @Autowired private RestTemplate restTemplate; @GetMapping("user/{id:\\d+}") public User getUser(@PathVariable Long id) { Map params = new HashMap<>(); params.put("id", id); URI uri = UriComponentsBuilder.fromUriString("http://Server-Provider/user/{id}") .build().expand(params).encode().toUri(); return this.restTemplate.getForEntity(uri, User.class).getBody(); } @GetMapping("user") public List getUsers() { return this.restTemplate.getForObject("http://Server-Provider/user", List.class); } @GetMapping("user/add") public String addUser() { User user = new User(1L, "mrbird", "123456"); HttpStatus status = this.restTemplate.postForEntity("http://Server-Provider/user", user, null).getStatusCode(); if (status.is2xxSuccessful()) { return "新增用户成功"; } else { return "新增用户失败"; } } @GetMapping("user/update") public void updateUser() { User user = new User(1L, "mrbird", "123456"); this.restTemplate.put("http://Server-Provider/user", user); } @GetMapping("user/delete/{id:\\d+}") public void deleteUser(@PathVariable Long id) { this.restTemplate.delete("http://Server-Provider/user/{1}", id); } } ================================================ FILE: 29.Spring-Cloud-Ribbon-LoadBalance/Ribbon-Consumer/src/main/java/com/example/demo/domain/User.java ================================================ package com.example.demo.domain; import java.io.Serializable; public class User implements Serializable { private static final long serialVersionUID = 1339434510787399891L; private Long id; private String username; private String password; public User() { } public User(Long id, String username, String password) { this.id = id; this.username = username; this.password = password; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", password='" + password + '\'' + '}'; } } ================================================ FILE: 29.Spring-Cloud-Ribbon-LoadBalance/Ribbon-Consumer/src/main/resources/application.yml ================================================ server: port: 9000 spring: application: name: Server-Consumer eureka: client: serviceUrl: defaultZone: http://mrbird:123456@peer1:8080/eureka/,http://mrbird:123456@peer2:8081/eureka/ ================================================ FILE: 30.Spring-Cloud-Hystrix-Circuit-Breaker/Eureka-Client/pom.xml ================================================ 4.0.0 com.example Eureka-Client 0.0.1-SNAPSHOT jar Eureka-Client Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.13.RELEASE UTF-8 UTF-8 1.8 org.springframework.cloud spring-cloud-dependencies Edgware.SR3 pom import org.springframework.cloud spring-cloud-starter-eureka org.springframework.boot spring-boot-starter org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 30.Spring-Cloud-Hystrix-Circuit-Breaker/Eureka-Client/src/main/java/com/example/demo/DemoApplication.java ================================================ package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; @EnableDiscoveryClient @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ================================================ FILE: 30.Spring-Cloud-Hystrix-Circuit-Breaker/Eureka-Client/src/main/java/com/example/demo/controller/TestController.java ================================================ package com.example.demo.controller; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class TestController { private Logger log = LoggerFactory.getLogger(this.getClass()); @Autowired private DiscoveryClient client; @GetMapping("/info") public String info() { @SuppressWarnings("deprecation") ServiceInstance instance = client.getLocalServiceInstance(); String info = "host:" + instance.getHost() + ",service_id:" + instance.getServiceId(); log.info(info); return info; } @GetMapping("/hello") public String hello() { return "hello world"; } } ================================================ FILE: 30.Spring-Cloud-Hystrix-Circuit-Breaker/Eureka-Client/src/main/java/com/example/demo/controller/UserController.java ================================================ package com.example.demo.controller; import com.example.demo.domain.User; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.*; import java.util.ArrayList; import java.util.List; @RestController @RequestMapping("user") public class UserController { private Logger log = LoggerFactory.getLogger(this.getClass()); @GetMapping("/{id:\\d+}") public User get(@PathVariable Long id) { log.info("获取用户id为 " + id + "的信息"); return new User(id, "mrbird", "123456"); } @GetMapping("users") public List get(String ids) { log.info("批量获取用户信息"); List list = new ArrayList<>(); for (String id : ids.split(",")) { list.add(new User(Long.valueOf(id), "user" + id, "123456")); } return list; } @GetMapping public List get() { List list = new ArrayList<>(); list.add(new User(1L, "mrbird", "123456")); list.add(new User(2L, "scott", "123456")); log.info("获取用户信息 " + list); return list; } @PostMapping public void add(@RequestBody User user) { log.info("新增用户成功 " + user); } @PutMapping public void update(@RequestBody User user) { log.info("更新用户成功 " + user); } @DeleteMapping("/{id:\\d+}") public void delete(@PathVariable Long id) { log.info("删除用户成功 " + id); } } ================================================ FILE: 30.Spring-Cloud-Hystrix-Circuit-Breaker/Eureka-Client/src/main/java/com/example/demo/domain/User.java ================================================ package com.example.demo.domain; import java.io.Serializable; public class User implements Serializable { private static final long serialVersionUID = 1339434510787399891L; private Long id; private String username; private String password; public User() { } public User(Long id, String username, String password) { this.id = id; this.username = username; this.password = password; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", password='" + password + '\'' + '}'; } } ================================================ FILE: 30.Spring-Cloud-Hystrix-Circuit-Breaker/Eureka-Client/src/main/resources/application.yml ================================================ server: port: 8082 spring: application: name: Server-Provider eureka: client: register-with-eureka: true fetch-registry: true serviceUrl: defaultZone: http://mrbird:123456@peer1:8080/eureka/,http://mrbird:123456@peer2:8081/eureka/ ================================================ FILE: 30.Spring-Cloud-Hystrix-Circuit-Breaker/Eureka-Service/pom.xml ================================================ 4.0.0 com.example Eureka-Service 0.0.1-SNAPSHOT jar Eureka-Service Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.13.RELEASE UTF-8 UTF-8 1.8 org.springframework.cloud spring-cloud-dependencies Edgware.SR3 pom import org.springframework.cloud spring-cloud-starter-eureka-server org.springframework.boot spring-boot-starter-security nexus-aliyun Nexus aliyun http://maven.aliyun.com/nexus/content/groups/public org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 30.Spring-Cloud-Hystrix-Circuit-Breaker/Eureka-Service/src/main/java/com/example/demo/DemoApplication.java ================================================ package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @EnableEurekaServer @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ================================================ FILE: 30.Spring-Cloud-Hystrix-Circuit-Breaker/Eureka-Service/src/main/resources/application-peer1.yml ================================================ server: port: 8080 spring: application: name: Eureka-Server eureka: instance: hostname: peer1 client: serviceUrl: defaultZone: http://mrbird:123456@peer2:8081/eureka/ server: enable-self-preservation: false ================================================ FILE: 30.Spring-Cloud-Hystrix-Circuit-Breaker/Eureka-Service/src/main/resources/application-peer2.yml ================================================ server: port: 8081 spring: application: name: Eureka-Server eureka: instance: hostname: peer2 client: serviceUrl: defaultZone: http://mrbird:123456@peer1:8080/eureka/ server: enable-self-preservation: false ================================================ FILE: 30.Spring-Cloud-Hystrix-Circuit-Breaker/Eureka-Service/src/main/resources/application.yml ================================================ security: basic: enabled: true user: name: mrbird password: 123456 spring: profiles: active: peer1 ================================================ FILE: 30.Spring-Cloud-Hystrix-Circuit-Breaker/Ribbon-Consumer/pom.xml ================================================ 4.0.0 com.example Ribbon-Consumer 0.0.1-SNAPSHOT jar Ribbon-Consumer Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.13.RELEASE UTF-8 UTF-8 1.8 org.springframework.cloud spring-cloud-dependencies Edgware.SR3 pom import org.springframework.cloud spring-cloud-starter-eureka org.springframework.boot spring-boot-starter org.springframework.cloud spring-cloud-starter-ribbon org.springframework.cloud spring-cloud-starter-hystrix org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 30.Spring-Cloud-Hystrix-Circuit-Breaker/Ribbon-Consumer/src/main/java/com/example/demo/DemoApplication.java ================================================ package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.cloud.client.SpringCloudApplication; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; @SpringCloudApplication public class DemoApplication { @Bean @LoadBalanced RestTemplate restTemplate() { return new RestTemplate(); } public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ================================================ FILE: 30.Spring-Cloud-Hystrix-Circuit-Breaker/Ribbon-Consumer/src/main/java/com/example/demo/Service/UserService.java ================================================ package com.example.demo.Service; import com.example.demo.domain.User; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCollapser; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty; import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheKey; import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheRemove; import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheResult; import com.netflix.hystrix.contrib.javanica.command.AsyncResult; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Service; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.client.RestTemplate; import java.util.Arrays; import java.util.List; import java.util.concurrent.Future; /** * @author MrBird */ @Service("userService") public class UserService { private Logger log = LoggerFactory.getLogger(this.getClass()); @Autowired private RestTemplate restTemplate; @HystrixCollapser(batchMethod = "findUserBatch", collapserProperties = { @HystrixProperty(name = "timerDelayInMilliseconds", value = "100") }) public Future findUser(Long id) { log.info("获取单个用户信息"); // return new AsyncResult() { // @Override // public User invoke() { // return restTemplate.getForObject("http://Server-Provider/user/{id}", User.class, id); // } // }; return null; } @HystrixCommand public List findUserBatch(List ids) { log.info("批量获取用户信息,ids: " + ids); User[] users = restTemplate.getForObject("http://Server-Provider/user/users?ids={1}", User[].class, StringUtils.join(ids, ",")); return Arrays.asList(users); } public String getCacheKey(Long id) { return String.valueOf(id); } @CacheResult(cacheKeyMethod = "getCacheKey") @HystrixCommand(fallbackMethod = "getUserDefault", commandKey = "getUserById", groupKey = "userGroup", threadPoolKey = "getUserThread") public User getUser(Long id) { log.info("获取用户信息"); return restTemplate.getForObject("http://Server-Provider/user/{id}", User.class, id); } @HystrixCommand(fallbackMethod = "getUserDefault2") public User getUserDefault(Long id) { String a = null; // 测试服务降级 a.toString(); User user = new User(); user.setId(-1L); user.setUsername("defaultUser"); user.setPassword("123456"); return user; } public User getUserDefault2(Long id, Throwable e) { System.out.println(e.getMessage()); User user = new User(); user.setId(-2L); user.setUsername("defaultUser2"); user.setPassword("123456"); return user; } public List getUsers() { return this.restTemplate.getForObject("http://Server-Provider/user", List.class); } public String addUser() { User user = new User(1L, "mrbird", "123456"); HttpStatus status = this.restTemplate.postForEntity("http://Server-Provider/user", user, null).getStatusCode(); if (status.is2xxSuccessful()) { return "新增用户成功"; } else { return "新增用户失败"; } } @CacheRemove(commandKey = "getUserById") @HystrixCommand public void updateUser(@CacheKey("id") User user) { this.restTemplate.put("http://Server-Provider/user", user); } public void deleteUser(@PathVariable Long id) { this.restTemplate.delete("http://Server-Provider/user/{1}", id); } } ================================================ FILE: 30.Spring-Cloud-Hystrix-Circuit-Breaker/Ribbon-Consumer/src/main/java/com/example/demo/controller/TestController.java ================================================ package com.example.demo.controller; import com.example.demo.Service.UserService; import com.example.demo.domain.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; @RestController public class TestController { @Autowired private UserService userService; @GetMapping("testRequestMerge") public void testRequerstMerge() throws InterruptedException, ExecutionException { Future f1 = userService.findUser(1L); Future f2 = userService.findUser(2L); Future f3 = userService.findUser(3L); f1.get(); f2.get(); f3.get(); Thread.sleep(200); Future f4 = userService.findUser(4L); f4.get(); } @GetMapping("testCache") public void testCache() { userService.getUser(1L); userService.getUser(1L); userService.getUser(1L); } @GetMapping("user/{id}") public User getUser(@PathVariable Long id) { return userService.getUser(id); } @GetMapping("user") public List getUsers() { return userService.getUsers(); } @GetMapping("user/add") public String addUser() { return userService.addUser(); } @GetMapping("user/update") public void updateUser() { userService.updateUser(new User(1L, "mrbird", "123456")); } @GetMapping("user/delete/{id:\\d+}") public void deleteUser(@PathVariable Long id) { userService.deleteUser(id); } } ================================================ FILE: 30.Spring-Cloud-Hystrix-Circuit-Breaker/Ribbon-Consumer/src/main/java/com/example/demo/domain/User.java ================================================ package com.example.demo.domain; import java.io.Serializable; public class User implements Serializable { private static final long serialVersionUID = 1339434510787399891L; private Long id; private String username; private String password; public User() { } public User(Long id, String username, String password) { this.id = id; this.username = username; this.password = password; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", password='" + password + '\'' + '}'; } } ================================================ FILE: 30.Spring-Cloud-Hystrix-Circuit-Breaker/Ribbon-Consumer/src/main/java/com/example/demo/filter/HystrixRequestContextServletFilter.java ================================================ package com.example.demo.filter; import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext; import org.springframework.stereotype.Component; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import java.io.IOException; /** * @author MrBird */ @Component @WebFilter(filterName = "hystrixRequestContextServletFilter", urlPatterns = "/*", asyncSupported = true) public class HystrixRequestContextServletFilter implements Filter { @Override public void init(FilterConfig filterConfig) { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HystrixRequestContext context = HystrixRequestContext.initializeContext(); filterChain.doFilter(servletRequest, servletResponse); context.close(); } @Override public void destroy() { } } ================================================ FILE: 30.Spring-Cloud-Hystrix-Circuit-Breaker/Ribbon-Consumer/src/main/resources/application.yml ================================================ server: port: 9000 spring: application: name: Server-Consumer eureka: client: serviceUrl: defaultZone: http://mrbird:123456@peer1:8080/eureka/,http://mrbird:123456@peer2:8081/eureka/ ================================================ FILE: 31.Spring-Cloud-Hystrix-Dashboard-Turbine/Eureka-Client/pom.xml ================================================ 4.0.0 com.example Eureka-Client 0.0.1-SNAPSHOT jar Eureka-Client Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.13.RELEASE UTF-8 UTF-8 1.8 org.springframework.cloud spring-cloud-dependencies Edgware.SR3 pom import org.springframework.cloud spring-cloud-starter-eureka org.springframework.boot spring-boot-starter org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 31.Spring-Cloud-Hystrix-Dashboard-Turbine/Eureka-Client/src/main/java/com/example/demo/DemoApplication.java ================================================ package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; @EnableDiscoveryClient @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ================================================ FILE: 31.Spring-Cloud-Hystrix-Dashboard-Turbine/Eureka-Client/src/main/java/com/example/demo/controller/TestController.java ================================================ package com.example.demo.controller; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class TestController { private Logger log = LoggerFactory.getLogger(this.getClass()); @Autowired private DiscoveryClient client; @GetMapping("/info") public String info() { @SuppressWarnings("deprecation") ServiceInstance instance = client.getLocalServiceInstance(); String info = "host:" + instance.getHost() + ",service_id:" + instance.getServiceId(); log.info(info); return info; } @GetMapping("/hello") public String hello() { return "hello world"; } } ================================================ FILE: 31.Spring-Cloud-Hystrix-Dashboard-Turbine/Eureka-Client/src/main/java/com/example/demo/controller/UserController.java ================================================ package com.example.demo.controller; import com.example.demo.domain.User; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.*; import java.util.ArrayList; import java.util.List; @RestController @RequestMapping("user") public class UserController { private Logger log = LoggerFactory.getLogger(this.getClass()); @GetMapping("/{id:\\d+}") public User get(@PathVariable Long id) { log.info("获取用户id为 " + id + "的信息"); return new User(id, "mrbird", "123456"); } @GetMapping("users") public List get(String ids) { log.info("批量获取用户信息"); List list = new ArrayList<>(); for (String id : ids.split(",")) { list.add(new User(Long.valueOf(id), "user" + id, "123456")); } return list; } @GetMapping public List get() { List list = new ArrayList<>(); list.add(new User(1L, "mrbird", "123456")); list.add(new User(2L, "scott", "123456")); log.info("获取用户信息 " + list); return list; } @PostMapping public void add(@RequestBody User user) { log.info("新增用户成功 " + user); } @PutMapping public void update(@RequestBody User user) { log.info("更新用户成功 " + user); } @DeleteMapping("/{id:\\d+}") public void delete(@PathVariable Long id) { log.info("删除用户成功 " + id); } } ================================================ FILE: 31.Spring-Cloud-Hystrix-Dashboard-Turbine/Eureka-Client/src/main/java/com/example/demo/domain/User.java ================================================ package com.example.demo.domain; import java.io.Serializable; public class User implements Serializable { private static final long serialVersionUID = 1339434510787399891L; private Long id; private String username; private String password; public User() { } public User(Long id, String username, String password) { this.id = id; this.username = username; this.password = password; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", password='" + password + '\'' + '}'; } } ================================================ FILE: 31.Spring-Cloud-Hystrix-Dashboard-Turbine/Eureka-Client/src/main/resources/application.yml ================================================ server: port: 8082 spring: application: name: Server-Provider eureka: client: register-with-eureka: true fetch-registry: true serviceUrl: defaultZone: http://mrbird:123456@peer1:8080/eureka/,http://mrbird:123456@peer2:8081/eureka/ ================================================ FILE: 31.Spring-Cloud-Hystrix-Dashboard-Turbine/Eureka-Service/pom.xml ================================================ 4.0.0 com.example Eureka-Service 0.0.1-SNAPSHOT jar Eureka-Service Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.13.RELEASE UTF-8 UTF-8 1.8 org.springframework.cloud spring-cloud-dependencies Edgware.SR3 pom import org.springframework.cloud spring-cloud-starter-eureka-server org.springframework.boot spring-boot-starter-security nexus-aliyun Nexus aliyun http://maven.aliyun.com/nexus/content/groups/public org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 31.Spring-Cloud-Hystrix-Dashboard-Turbine/Eureka-Service/src/main/java/com/example/demo/DemoApplication.java ================================================ package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @EnableEurekaServer @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ================================================ FILE: 31.Spring-Cloud-Hystrix-Dashboard-Turbine/Eureka-Service/src/main/resources/application-peer1.yml ================================================ server: port: 8080 spring: application: name: Eureka-Server eureka: instance: hostname: peer1 client: serviceUrl: defaultZone: http://mrbird:123456@peer2:8081/eureka/ server: enable-self-preservation: false ================================================ FILE: 31.Spring-Cloud-Hystrix-Dashboard-Turbine/Eureka-Service/src/main/resources/application-peer2.yml ================================================ server: port: 8081 spring: application: name: Eureka-Server eureka: instance: hostname: peer2 client: serviceUrl: defaultZone: http://mrbird:123456@peer1:8080/eureka/ server: enable-self-preservation: false ================================================ FILE: 31.Spring-Cloud-Hystrix-Dashboard-Turbine/Eureka-Service/src/main/resources/application.yml ================================================ security: basic: enabled: true user: name: mrbird password: 123456 spring: profiles: active: peer1 ================================================ FILE: 31.Spring-Cloud-Hystrix-Dashboard-Turbine/Hystrix-Dashboard/pom.xml ================================================ 4.0.0 com.example Hystrix-Dashboard 0.0.1-SNAPSHOT jar Hystrix-Dashboard Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.13.RELEASE UTF-8 UTF-8 1.8 org.springframework.cloud spring-cloud-dependencies Edgware.SR3 pom import org.springframework.cloud spring-cloud-starter-hystrix org.springframework.cloud spring-cloud-starter-hystrix-dashboard org.springframework.boot spring-boot-starter-actuator org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 31.Spring-Cloud-Hystrix-Dashboard-Turbine/Hystrix-Dashboard/src/main/java/com/example/demo/DemoApplication.java ================================================ package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard; @SpringBootApplication @EnableHystrixDashboard public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ================================================ FILE: 31.Spring-Cloud-Hystrix-Dashboard-Turbine/Hystrix-Dashboard/src/main/resources/application.yml ================================================ spring: application: name: Hystrix-Dashboard server: port: 9002 ================================================ FILE: 31.Spring-Cloud-Hystrix-Dashboard-Turbine/Ribbon-Consumer/pom.xml ================================================ 4.0.0 com.example Ribbon-Consumer 0.0.1-SNAPSHOT jar Ribbon-Consumer Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.13.RELEASE UTF-8 UTF-8 1.8 org.springframework.cloud spring-cloud-dependencies Edgware.SR3 pom import org.springframework.cloud spring-cloud-starter-eureka org.springframework.boot spring-boot-starter org.springframework.cloud spring-cloud-starter-ribbon org.springframework.cloud spring-cloud-starter-hystrix org.springframework.boot spring-boot-starter-actuator org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 31.Spring-Cloud-Hystrix-Dashboard-Turbine/Ribbon-Consumer/src/main/java/com/example/demo/DemoApplication.java ================================================ package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.cloud.client.SpringCloudApplication; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; @SpringCloudApplication public class DemoApplication { @Bean @LoadBalanced RestTemplate restTemplate() { return new RestTemplate(); } public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ================================================ FILE: 31.Spring-Cloud-Hystrix-Dashboard-Turbine/Ribbon-Consumer/src/main/java/com/example/demo/Service/UserService.java ================================================ package com.example.demo.Service; import com.example.demo.domain.User; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCollapser; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty; import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheKey; import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheRemove; import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheResult; import com.netflix.hystrix.contrib.javanica.command.AsyncResult; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Service; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.client.RestTemplate; import java.util.Arrays; import java.util.List; import java.util.concurrent.Future; /** * @author MrBird */ @Service("userService") public class UserService { private Logger log = LoggerFactory.getLogger(this.getClass()); @Autowired private RestTemplate restTemplate; @HystrixCollapser(batchMethod = "findUserBatch", collapserProperties = { @HystrixProperty(name = "timerDelayInMilliseconds", value = "100") }) public Future findUser(Long id) { log.info("获取单个用户信息"); // return new AsyncResult() { // @Override // public User invoke() { // return restTemplate.getForObject("http://Server-Provider/user/{id}", User.class, id); // } // }; return null; } @HystrixCommand public List findUserBatch(List ids) { log.info("批量获取用户信息,ids: " + ids); User[] users = restTemplate.getForObject("http://Server-Provider/user/users?ids={1}", User[].class, StringUtils.join(ids, ",")); return Arrays.asList(users); } public String getCacheKey(Long id) { return String.valueOf(id); } @CacheResult(cacheKeyMethod = "getCacheKey") @HystrixCommand(fallbackMethod = "getUserDefault", commandKey = "getUserById", groupKey = "userGroup", threadPoolKey = "getUserThread") public User getUser(Long id) { log.info("获取用户信息"); return restTemplate.getForObject("http://Server-Provider/user/{id}", User.class, id); } @HystrixCommand(fallbackMethod = "getUserDefault2") public User getUserDefault(Long id) { String a = null; // 测试服务降级 a.toString(); User user = new User(); user.setId(-1L); user.setUsername("defaultUser"); user.setPassword("123456"); return user; } public User getUserDefault2(Long id, Throwable e) { System.out.println(e.getMessage()); User user = new User(); user.setId(-2L); user.setUsername("defaultUser2"); user.setPassword("123456"); return user; } public List getUsers() { return this.restTemplate.getForObject("http://Server-Provider/user", List.class); } public String addUser() { User user = new User(1L, "mrbird", "123456"); HttpStatus status = this.restTemplate.postForEntity("http://Server-Provider/user", user, null).getStatusCode(); if (status.is2xxSuccessful()) { return "新增用户成功"; } else { return "新增用户失败"; } } @CacheRemove(commandKey = "getUserById") @HystrixCommand public void updateUser(@CacheKey("id") User user) { this.restTemplate.put("http://Server-Provider/user", user); } public void deleteUser(@PathVariable Long id) { this.restTemplate.delete("http://Server-Provider/user/{1}", id); } } ================================================ FILE: 31.Spring-Cloud-Hystrix-Dashboard-Turbine/Ribbon-Consumer/src/main/java/com/example/demo/controller/TestController.java ================================================ package com.example.demo.controller; import com.example.demo.Service.UserService; import com.example.demo.domain.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; @RestController public class TestController { @Autowired private UserService userService; @GetMapping("testRequestMerge") public void testRequerstMerge() throws InterruptedException, ExecutionException { Future f1 = userService.findUser(1L); Future f2 = userService.findUser(2L); Future f3 = userService.findUser(3L); f1.get(); f2.get(); f3.get(); Thread.sleep(200); Future f4 = userService.findUser(4L); f4.get(); } @GetMapping("testCache") public void testCache() { userService.getUser(1L); userService.getUser(1L); userService.getUser(1L); } @GetMapping("user/{id}") public User getUser(@PathVariable Long id) { return userService.getUser(id); } @GetMapping("user") public List getUsers() { return userService.getUsers(); } @GetMapping("user/add") public String addUser() { return userService.addUser(); } @GetMapping("user/update") public void updateUser() { userService.updateUser(new User(1L, "mrbird", "123456")); } @GetMapping("user/delete/{id:\\d+}") public void deleteUser(@PathVariable Long id) { userService.deleteUser(id); } } ================================================ FILE: 31.Spring-Cloud-Hystrix-Dashboard-Turbine/Ribbon-Consumer/src/main/java/com/example/demo/domain/User.java ================================================ package com.example.demo.domain; import java.io.Serializable; public class User implements Serializable { private static final long serialVersionUID = 1339434510787399891L; private Long id; private String username; private String password; public User() { } public User(Long id, String username, String password) { this.id = id; this.username = username; this.password = password; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", password='" + password + '\'' + '}'; } } ================================================ FILE: 31.Spring-Cloud-Hystrix-Dashboard-Turbine/Ribbon-Consumer/src/main/java/com/example/demo/filter/HystrixRequestContextServletFilter.java ================================================ package com.example.demo.filter; import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext; import org.springframework.stereotype.Component; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import java.io.IOException; /** * @author MrBird */ @Component @WebFilter(filterName = "hystrixRequestContextServletFilter", urlPatterns = "/*", asyncSupported = true) public class HystrixRequestContextServletFilter implements Filter { @Override public void init(FilterConfig filterConfig) { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HystrixRequestContext context = HystrixRequestContext.initializeContext(); filterChain.doFilter(servletRequest, servletResponse); context.close(); } @Override public void destroy() { } } ================================================ FILE: 31.Spring-Cloud-Hystrix-Dashboard-Turbine/Ribbon-Consumer/src/main/resources/application.yml ================================================ server: port: 9000 spring: application: name: Ribbon-Consumer eureka: client: serviceUrl: defaultZone: http://mrbird:123456@peer1:8080/eureka/,http://mrbird:123456@peer2:8081/eureka/ ================================================ FILE: 31.Spring-Cloud-Hystrix-Dashboard-Turbine/Turbine/pom.xml ================================================ 4.0.0 com.example Turbine 0.0.1-SNAPSHOT jar Turbine Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.13.RELEASE UTF-8 UTF-8 1.8 org.springframework.cloud spring-cloud-dependencies Edgware.SR3 pom import org.springframework.cloud spring-cloud-starter-turbine org.springframework.boot spring-boot-starter-actuator org.springframework.cloud spring-cloud-starter-eureka org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 31.Spring-Cloud-Hystrix-Dashboard-Turbine/Turbine/src/main/java/com/example/demo/DemoApplication.java ================================================ package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.netflix.turbine.EnableTurbine; @SpringBootApplication @EnableTurbine @EnableDiscoveryClient public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ================================================ FILE: 31.Spring-Cloud-Hystrix-Dashboard-Turbine/Turbine/src/main/resources/application.yml ================================================ spring: application: name: Turbine server: port: 9003 eureka: client: serviceUrl: defaultZone: http://mrbird:123456@peer1:8080/eureka/,http://mrbird:123456@peer2:8081/eureka/ turbine: app-config: Ribbon-Consumer cluster-name-expression: new String('default') combine-host-port: true ================================================ FILE: 32.Spring-Cloud-Hystrix-Dashboard-Turbine-RabbitMQ/Eureka-Client/pom.xml ================================================ 4.0.0 com.example Eureka-Client 0.0.1-SNAPSHOT jar Eureka-Client Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.13.RELEASE UTF-8 UTF-8 1.8 org.springframework.cloud spring-cloud-dependencies Edgware.SR3 pom import org.springframework.cloud spring-cloud-starter-eureka org.springframework.boot spring-boot-starter org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 32.Spring-Cloud-Hystrix-Dashboard-Turbine-RabbitMQ/Eureka-Client/src/main/java/com/example/demo/DemoApplication.java ================================================ package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; @EnableDiscoveryClient @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ================================================ FILE: 32.Spring-Cloud-Hystrix-Dashboard-Turbine-RabbitMQ/Eureka-Client/src/main/java/com/example/demo/controller/TestController.java ================================================ package com.example.demo.controller; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class TestController { private Logger log = LoggerFactory.getLogger(this.getClass()); @Autowired private DiscoveryClient client; @GetMapping("/info") public String info() { @SuppressWarnings("deprecation") ServiceInstance instance = client.getLocalServiceInstance(); String info = "host:" + instance.getHost() + ",service_id:" + instance.getServiceId(); log.info(info); return info; } @GetMapping("/hello") public String hello() { return "hello world"; } } ================================================ FILE: 32.Spring-Cloud-Hystrix-Dashboard-Turbine-RabbitMQ/Eureka-Client/src/main/java/com/example/demo/controller/UserController.java ================================================ package com.example.demo.controller; import com.example.demo.domain.User; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.*; import java.util.ArrayList; import java.util.List; @RestController @RequestMapping("user") public class UserController { private Logger log = LoggerFactory.getLogger(this.getClass()); @GetMapping("/{id:\\d+}") public User get(@PathVariable Long id) { log.info("获取用户id为 " + id + "的信息"); return new User(id, "mrbird", "123456"); } @GetMapping("users") public List get(String ids) { log.info("批量获取用户信息"); List list = new ArrayList<>(); for (String id : ids.split(",")) { list.add(new User(Long.valueOf(id), "user" + id, "123456")); } return list; } @GetMapping public List get() { List list = new ArrayList<>(); list.add(new User(1L, "mrbird", "123456")); list.add(new User(2L, "scott", "123456")); log.info("获取用户信息 " + list); return list; } @PostMapping public void add(@RequestBody User user) { log.info("新增用户成功 " + user); } @PutMapping public void update(@RequestBody User user) { log.info("更新用户成功 " + user); } @DeleteMapping("/{id:\\d+}") public void delete(@PathVariable Long id) { log.info("删除用户成功 " + id); } } ================================================ FILE: 32.Spring-Cloud-Hystrix-Dashboard-Turbine-RabbitMQ/Eureka-Client/src/main/java/com/example/demo/domain/User.java ================================================ package com.example.demo.domain; import java.io.Serializable; public class User implements Serializable { private static final long serialVersionUID = 1339434510787399891L; private Long id; private String username; private String password; public User() { } public User(Long id, String username, String password) { this.id = id; this.username = username; this.password = password; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", password='" + password + '\'' + '}'; } } ================================================ FILE: 32.Spring-Cloud-Hystrix-Dashboard-Turbine-RabbitMQ/Eureka-Client/src/main/resources/application.yml ================================================ server: port: 8082 spring: application: name: Server-Provider eureka: client: register-with-eureka: true fetch-registry: true serviceUrl: defaultZone: http://mrbird:123456@peer1:8080/eureka/,http://mrbird:123456@peer2:8081/eureka/ ================================================ FILE: 32.Spring-Cloud-Hystrix-Dashboard-Turbine-RabbitMQ/Eureka-Service/pom.xml ================================================ 4.0.0 com.example Eureka-Service 0.0.1-SNAPSHOT jar Eureka-Service Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.13.RELEASE UTF-8 UTF-8 1.8 org.springframework.cloud spring-cloud-dependencies Edgware.SR3 pom import org.springframework.cloud spring-cloud-starter-eureka-server org.springframework.boot spring-boot-starter-security nexus-aliyun Nexus aliyun http://maven.aliyun.com/nexus/content/groups/public org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 32.Spring-Cloud-Hystrix-Dashboard-Turbine-RabbitMQ/Eureka-Service/src/main/java/com/example/demo/DemoApplication.java ================================================ package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @EnableEurekaServer @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ================================================ FILE: 32.Spring-Cloud-Hystrix-Dashboard-Turbine-RabbitMQ/Eureka-Service/src/main/resources/application-peer1.yml ================================================ server: port: 8080 spring: application: name: Eureka-Server eureka: instance: hostname: peer1 client: serviceUrl: defaultZone: http://mrbird:123456@peer2:8081/eureka/ server: enable-self-preservation: false ================================================ FILE: 32.Spring-Cloud-Hystrix-Dashboard-Turbine-RabbitMQ/Eureka-Service/src/main/resources/application-peer2.yml ================================================ server: port: 8081 spring: application: name: Eureka-Server eureka: instance: hostname: peer2 client: serviceUrl: defaultZone: http://mrbird:123456@peer1:8080/eureka/ server: enable-self-preservation: false ================================================ FILE: 32.Spring-Cloud-Hystrix-Dashboard-Turbine-RabbitMQ/Eureka-Service/src/main/resources/application.yml ================================================ security: basic: enabled: true user: name: mrbird password: 123456 spring: profiles: active: peer1 ================================================ FILE: 32.Spring-Cloud-Hystrix-Dashboard-Turbine-RabbitMQ/Hystrix-Dashboard/pom.xml ================================================ 4.0.0 com.example Hystrix-Dashboard 0.0.1-SNAPSHOT jar Hystrix-Dashboard Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.13.RELEASE UTF-8 UTF-8 1.8 org.springframework.cloud spring-cloud-dependencies Edgware.SR3 pom import org.springframework.cloud spring-cloud-starter-hystrix org.springframework.cloud spring-cloud-starter-hystrix-dashboard org.springframework.boot spring-boot-starter-actuator org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 32.Spring-Cloud-Hystrix-Dashboard-Turbine-RabbitMQ/Hystrix-Dashboard/src/main/java/com/example/demo/DemoApplication.java ================================================ package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard; @SpringBootApplication @EnableHystrixDashboard public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ================================================ FILE: 32.Spring-Cloud-Hystrix-Dashboard-Turbine-RabbitMQ/Hystrix-Dashboard/src/main/resources/application.yml ================================================ spring: application: name: Hystrix-Dashboard server: port: 9002 ================================================ FILE: 32.Spring-Cloud-Hystrix-Dashboard-Turbine-RabbitMQ/Ribbon-Consumer/pom.xml ================================================ 4.0.0 com.example Ribbon-Consumer 0.0.1-SNAPSHOT jar Ribbon-Consumer Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.13.RELEASE UTF-8 UTF-8 1.8 org.springframework.cloud spring-cloud-dependencies Edgware.SR3 pom import org.springframework.cloud spring-cloud-starter-eureka org.springframework.boot spring-boot-starter org.springframework.cloud spring-cloud-starter-ribbon org.springframework.cloud spring-cloud-starter-hystrix org.springframework.boot spring-boot-starter-actuator org.springframework.cloud spring-cloud-netflix-hystrix-stream org.springframework.cloud spring-cloud-starter-stream-rabbit org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 32.Spring-Cloud-Hystrix-Dashboard-Turbine-RabbitMQ/Ribbon-Consumer/src/main/java/com/example/demo/DemoApplication.java ================================================ package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.cloud.client.SpringCloudApplication; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; @SpringCloudApplication public class DemoApplication { @Bean @LoadBalanced RestTemplate restTemplate() { return new RestTemplate(); } public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ================================================ FILE: 32.Spring-Cloud-Hystrix-Dashboard-Turbine-RabbitMQ/Ribbon-Consumer/src/main/java/com/example/demo/Service/UserService.java ================================================ package com.example.demo.Service; import com.example.demo.domain.User; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCollapser; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty; import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheKey; import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheRemove; import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheResult; import com.netflix.hystrix.contrib.javanica.command.AsyncResult; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Service; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.client.RestTemplate; import java.util.Arrays; import java.util.List; import java.util.concurrent.Future; /** * @author MrBird */ @Service("userService") public class UserService { private Logger log = LoggerFactory.getLogger(this.getClass()); @Autowired private RestTemplate restTemplate; @HystrixCollapser(batchMethod = "findUserBatch", collapserProperties = { @HystrixProperty(name = "timerDelayInMilliseconds", value = "100") }) public Future findUser(Long id) { log.info("获取单个用户信息"); // return new AsyncResult() { // @Override // public User invoke() { // return restTemplate.getForObject("http://Server-Provider/user/{id}", User.class, id); // } // }; return null; } @HystrixCommand public List findUserBatch(List ids) { log.info("批量获取用户信息,ids: " + ids); User[] users = restTemplate.getForObject("http://Server-Provider/user/users?ids={1}", User[].class, StringUtils.join(ids, ",")); return Arrays.asList(users); } public String getCacheKey(Long id) { return String.valueOf(id); } @CacheResult(cacheKeyMethod = "getCacheKey") @HystrixCommand(fallbackMethod = "getUserDefault", commandKey = "getUserById", groupKey = "userGroup", threadPoolKey = "getUserThread") public User getUser(Long id) { log.info("获取用户信息"); return restTemplate.getForObject("http://Server-Provider/user/{id}", User.class, id); } @HystrixCommand(fallbackMethod = "getUserDefault2") public User getUserDefault(Long id) { String a = null; // 测试服务降级 a.toString(); User user = new User(); user.setId(-1L); user.setUsername("defaultUser"); user.setPassword("123456"); return user; } public User getUserDefault2(Long id, Throwable e) { System.out.println(e.getMessage()); User user = new User(); user.setId(-2L); user.setUsername("defaultUser2"); user.setPassword("123456"); return user; } public List getUsers() { return this.restTemplate.getForObject("http://Server-Provider/user", List.class); } public String addUser() { User user = new User(1L, "mrbird", "123456"); HttpStatus status = this.restTemplate.postForEntity("http://Server-Provider/user", user, null).getStatusCode(); if (status.is2xxSuccessful()) { return "新增用户成功"; } else { return "新增用户失败"; } } @CacheRemove(commandKey = "getUserById") @HystrixCommand public void updateUser(@CacheKey("id") User user) { this.restTemplate.put("http://Server-Provider/user", user); } public void deleteUser(@PathVariable Long id) { this.restTemplate.delete("http://Server-Provider/user/{1}", id); } } ================================================ FILE: 32.Spring-Cloud-Hystrix-Dashboard-Turbine-RabbitMQ/Ribbon-Consumer/src/main/java/com/example/demo/controller/TestController.java ================================================ package com.example.demo.controller; import com.example.demo.Service.UserService; import com.example.demo.domain.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; @RestController public class TestController { @Autowired private UserService userService; @GetMapping("testRequestMerge") public void testRequerstMerge() throws InterruptedException, ExecutionException { Future f1 = userService.findUser(1L); Future f2 = userService.findUser(2L); Future f3 = userService.findUser(3L); f1.get(); f2.get(); f3.get(); Thread.sleep(200); Future f4 = userService.findUser(4L); f4.get(); } @GetMapping("testCache") public void testCache() { userService.getUser(1L); userService.getUser(1L); userService.getUser(1L); } @GetMapping("user/{id}") public User getUser(@PathVariable Long id) { return userService.getUser(id); } @GetMapping("user") public List getUsers() { return userService.getUsers(); } @GetMapping("user/add") public String addUser() { return userService.addUser(); } @GetMapping("user/update") public void updateUser() { userService.updateUser(new User(1L, "mrbird", "123456")); } @GetMapping("user/delete/{id:\\d+}") public void deleteUser(@PathVariable Long id) { userService.deleteUser(id); } } ================================================ FILE: 32.Spring-Cloud-Hystrix-Dashboard-Turbine-RabbitMQ/Ribbon-Consumer/src/main/java/com/example/demo/domain/User.java ================================================ package com.example.demo.domain; import java.io.Serializable; public class User implements Serializable { private static final long serialVersionUID = 1339434510787399891L; private Long id; private String username; private String password; public User() { } public User(Long id, String username, String password) { this.id = id; this.username = username; this.password = password; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", password='" + password + '\'' + '}'; } } ================================================ FILE: 32.Spring-Cloud-Hystrix-Dashboard-Turbine-RabbitMQ/Ribbon-Consumer/src/main/java/com/example/demo/filter/HystrixRequestContextServletFilter.java ================================================ package com.example.demo.filter; import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext; import org.springframework.stereotype.Component; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import java.io.IOException; /** * @author MrBird */ @Component @WebFilter(filterName = "hystrixRequestContextServletFilter", urlPatterns = "/*", asyncSupported = true) public class HystrixRequestContextServletFilter implements Filter { @Override public void init(FilterConfig filterConfig) { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HystrixRequestContext context = HystrixRequestContext.initializeContext(); filterChain.doFilter(servletRequest, servletResponse); context.close(); } @Override public void destroy() { } } ================================================ FILE: 32.Spring-Cloud-Hystrix-Dashboard-Turbine-RabbitMQ/Ribbon-Consumer/src/main/resources/application.yml ================================================ server: port: 9000 spring: application: name: Ribbon-Consumer rabbitmq: host: localhost port: 5672 username: guest password: guest eureka: client: serviceUrl: defaultZone: http://mrbird:123456@peer1:8080/eureka/,http://mrbird:123456@peer2:8081/eureka/ ================================================ FILE: 32.Spring-Cloud-Hystrix-Dashboard-Turbine-RabbitMQ/Turbine-Stream/pom.xml ================================================ 4.0.0 com.example Turbine-Stream 0.0.1-SNAPSHOT jar Turbine-Stream Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.13.RELEASE UTF-8 UTF-8 1.8 org.springframework.cloud spring-cloud-dependencies Edgware.SR3 pom import org.springframework.boot spring-boot-starter-actuator org.springframework.cloud spring-cloud-starter-turbine-stream org.springframework.cloud spring-cloud-starter-stream-rabbit org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 32.Spring-Cloud-Hystrix-Dashboard-Turbine-RabbitMQ/Turbine-Stream/src/main/java/com/example/demo/DemoApplication.java ================================================ package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.turbine.stream.EnableTurbineStream; @SpringBootApplication @EnableTurbineStream public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ================================================ FILE: 32.Spring-Cloud-Hystrix-Dashboard-Turbine-RabbitMQ/Turbine-Stream/src/main/resources/application.yml ================================================ spring: application: name: Turbine rabbitmq: host: localhost port: 5672 username: guest password: guest server: port: 9003 ================================================ FILE: 33.Spring-Cloud-Feign-Declarative-REST-Client/Eureka-Client/pom.xml ================================================ 4.0.0 com.example Eureka-Client 0.0.1-SNAPSHOT jar Eureka-Client Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.13.RELEASE UTF-8 UTF-8 1.8 org.springframework.cloud spring-cloud-dependencies Edgware.SR3 pom import org.springframework.cloud spring-cloud-starter-eureka org.springframework.boot spring-boot-starter org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 33.Spring-Cloud-Feign-Declarative-REST-Client/Eureka-Client/src/main/java/com/example/demo/DemoApplication.java ================================================ package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; @EnableDiscoveryClient @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ================================================ FILE: 33.Spring-Cloud-Feign-Declarative-REST-Client/Eureka-Client/src/main/java/com/example/demo/controller/TestController.java ================================================ package com.example.demo.controller; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class TestController { private Logger log = LoggerFactory.getLogger(this.getClass()); @Autowired private DiscoveryClient client; @GetMapping("/info") public String info() { @SuppressWarnings("deprecation") ServiceInstance instance = client.getLocalServiceInstance(); String info = "host:" + instance.getHost() + ",service_id:" + instance.getServiceId(); log.info(info); return info; } @GetMapping("/hello") public String hello() { return "hello world"; } } ================================================ FILE: 33.Spring-Cloud-Feign-Declarative-REST-Client/Eureka-Client/src/main/java/com/example/demo/controller/UserController.java ================================================ package com.example.demo.controller; import com.example.demo.domain.User; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.*; import java.util.ArrayList; import java.util.List; @RestController @RequestMapping("user") public class UserController { private Logger log = LoggerFactory.getLogger(this.getClass()); @GetMapping("/{id:\\d+}") public User get(@PathVariable Long id) { log.info("获取用户id为 " + id + "的信息"); return new User(id, "mrbird", "123456"); } @GetMapping public List get() { List list = new ArrayList<>(); list.add(new User(1L, "mrbird", "123456")); list.add(new User(2L, "scott", "123456")); log.info("获取用户信息 " + list); return list; } @PostMapping public void add(@RequestBody User user) { log.info("新增用户成功 " + user); } @PutMapping public void update(@RequestBody User user) { log.info("更新用户成功 " + user); } @DeleteMapping("/{id:\\d+}") public void delete(@PathVariable Long id) { log.info("删除用户成功 " + id); } } ================================================ FILE: 33.Spring-Cloud-Feign-Declarative-REST-Client/Eureka-Client/src/main/java/com/example/demo/domain/User.java ================================================ package com.example.demo.domain; import java.io.Serializable; public class User implements Serializable { private static final long serialVersionUID = 1339434510787399891L; private Long id; private String username; private String password; public User() { } public User(Long id, String username, String password) { this.id = id; this.username = username; this.password = password; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", password='" + password + '\'' + '}'; } } ================================================ FILE: 33.Spring-Cloud-Feign-Declarative-REST-Client/Eureka-Client/src/main/resources/application.yml ================================================ server: port: 8082 spring: application: name: Server-Provider eureka: client: register-with-eureka: true fetch-registry: true serviceUrl: defaultZone: http://mrbird:123456@peer1:8080/eureka/,http://mrbird:123456@peer2:8081/eureka/ ================================================ FILE: 33.Spring-Cloud-Feign-Declarative-REST-Client/Eureka-Service/pom.xml ================================================ 4.0.0 com.example Eureka-Service 0.0.1-SNAPSHOT jar Eureka-Service Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.13.RELEASE UTF-8 UTF-8 1.8 org.springframework.cloud spring-cloud-dependencies Edgware.SR3 pom import org.springframework.cloud spring-cloud-starter-eureka-server org.springframework.boot spring-boot-starter-security nexus-aliyun Nexus aliyun http://maven.aliyun.com/nexus/content/groups/public org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 33.Spring-Cloud-Feign-Declarative-REST-Client/Eureka-Service/src/main/java/com/example/demo/DemoApplication.java ================================================ package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @EnableEurekaServer @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ================================================ FILE: 33.Spring-Cloud-Feign-Declarative-REST-Client/Eureka-Service/src/main/resources/application-peer1.yml ================================================ server: port: 8080 spring: application: name: Eureka-Server eureka: instance: hostname: peer1 client: serviceUrl: defaultZone: http://mrbird:123456@peer2:8081/eureka/ server: enable-self-preservation: false ================================================ FILE: 33.Spring-Cloud-Feign-Declarative-REST-Client/Eureka-Service/src/main/resources/application-peer2.yml ================================================ server: port: 8081 spring: application: name: Eureka-Server eureka: instance: hostname: peer2 client: serviceUrl: defaultZone: http://mrbird:123456@peer1:8080/eureka/ server: enable-self-preservation: false ================================================ FILE: 33.Spring-Cloud-Feign-Declarative-REST-Client/Eureka-Service/src/main/resources/application.yml ================================================ security: basic: enabled: true user: name: mrbird password: 123456 spring: profiles: active: peer1 ================================================ FILE: 33.Spring-Cloud-Feign-Declarative-REST-Client/Feign-Consumer/pom.xml ================================================ 4.0.0 com.example Feign-Consumer 0.0.1-SNAPSHOT jar Feign-Consumer Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.13.RELEASE UTF-8 UTF-8 1.8 org.springframework.cloud spring-cloud-dependencies Edgware.SR3 pom import org.springframework.cloud spring-cloud-starter-eureka org.springframework.boot spring-boot-starter org.springframework.cloud spring-cloud-starter-feign org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 33.Spring-Cloud-Feign-Declarative-REST-Client/Feign-Consumer/src/main/java/com/example/demo/DemoApplication.java ================================================ package com.example.demo; import feign.Logger; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.netflix.feign.EnableFeignClients; import org.springframework.context.annotation.Bean; @EnableDiscoveryClient @EnableFeignClients @SpringBootApplication public class DemoApplication { @Bean Logger.Level feignLoggerLevel() { return Logger.Level.FULL; } public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ================================================ FILE: 33.Spring-Cloud-Feign-Declarative-REST-Client/Feign-Consumer/src/main/java/com/example/demo/controller/TestController.java ================================================ package com.example.demo.controller; import com.example.demo.domain.User; import com.example.demo.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import java.util.List; @RestController public class TestController { @Autowired private UserService userService; @GetMapping("user/{id}") public User getUser(@PathVariable Long id) { return userService.get(id); } @GetMapping("user") public List getUsers() { return userService.get(); } @PostMapping("user") public void addUser() { User user = new User(1L, "mrbird", "123456"); userService.add(user); } @PutMapping("user") public void updateUser() { User user = new User(1L, "mrbird", "123456"); userService.update(user); } @DeleteMapping("user/{id}") public void deleteUser(@PathVariable Long id) { userService.delete(id); } } ================================================ FILE: 33.Spring-Cloud-Feign-Declarative-REST-Client/Feign-Consumer/src/main/java/com/example/demo/domain/User.java ================================================ package com.example.demo.domain; import java.io.Serializable; public class User implements Serializable { private static final long serialVersionUID = 1339434510787399891L; private Long id; private String username; private String password; public User() { } public User(Long id, String username, String password) { this.id = id; this.username = username; this.password = password; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", password='" + password + '\'' + '}'; } } ================================================ FILE: 33.Spring-Cloud-Feign-Declarative-REST-Client/Feign-Consumer/src/main/java/com/example/demo/service/UserService.java ================================================ package com.example.demo.service; import com.example.demo.domain.User; import org.springframework.cloud.netflix.feign.FeignClient; import org.springframework.web.bind.annotation.*; import java.util.List; /** * @author MrBird */ @FeignClient(value = "Server-Provider", fallback = UserServiceFallback.class) public interface UserService { @GetMapping("user/{id}") public User get(@PathVariable("id") Long id); @GetMapping("user") public List get(); @PostMapping("user") public void add(@RequestBody User user); @PutMapping("user") public void update(@RequestBody User user); @DeleteMapping("user/{id}") public void delete(@PathVariable("id") Long id); } ================================================ FILE: 33.Spring-Cloud-Feign-Declarative-REST-Client/Feign-Consumer/src/main/java/com/example/demo/service/UserServiceFallback.java ================================================ package com.example.demo.service; import com.example.demo.domain.User; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import java.util.List; /** * @author MrBird */ @Component public class UserServiceFallback implements UserService { private Logger log = LoggerFactory.getLogger(this.getClass()); @Override public User get(Long id) { return new User(-1L, "default", "123456"); } @Override public List get() { return null; } @Override public void add(User user) { log.info("test fallback"); } @Override public void update(User user) { log.info("test fallback"); } @Override public void delete(Long id) { log.info("test fallback"); } } ================================================ FILE: 33.Spring-Cloud-Feign-Declarative-REST-Client/Feign-Consumer/src/main/resources/application.yml ================================================ server: port: 9000 spring: application: name: Server-Consumer eureka: client: serviceUrl: defaultZone: http://mrbird:123456@peer1:8080/eureka/,http://mrbird:123456@peer2:8081/eureka/ feign: hystrix: enabled: true logging: level: com: example: demo: service: UserService: debug ================================================ FILE: 34.Start-Spring-Security/pom.xml ================================================ 4.0.0 cc.mrbird Security 1.0-SNAPSHOT jar Security Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.14.RELEASE UTF-8 UTF-8 1.8 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-security org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 34.Start-Spring-Security/src/main/java/cc/mrbird/SecurityApplication.java ================================================ package cc.mrbird; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class SecurityApplication { public static void main(String[] args) { SpringApplication.run(SecurityApplication.class, args); } } ================================================ FILE: 34.Start-Spring-Security/src/main/java/cc/mrbird/security/browser/BrowserSecurityConfig.java ================================================ package cc.mrbird.security.browser; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; @Configuration public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.formLogin() // 表单登录 // http.httpBasic() // HTTP Basic .and() .authorizeRequests() // 授权配置 .anyRequest() // 所有请求 .authenticated(); // 都需要认证 } } ================================================ FILE: 34.Start-Spring-Security/src/main/java/cc/mrbird/web/controller/TestController.java ================================================ package cc.mrbird.web.controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class TestController { @GetMapping("hello") public String hello() { return "hello spring security"; } } ================================================ FILE: 34.Start-Spring-Security/src/main/resources/application.yml ================================================ security: basic: enabled: true ================================================ FILE: 35.Spring-Security-Authentication/pom.xml ================================================ 4.0.0 cc.mrbird Security 1.0-SNAPSHOT jar Security Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.14.RELEASE UTF-8 UTF-8 1.8 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-security org.apache.commons commons-lang3 3.7 org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 35.Spring-Security-Authentication/src/main/java/cc/mrbird/SecurityApplication.java ================================================ package cc.mrbird; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class SecurityApplication { public static void main(String[] args) { SpringApplication.run(SecurityApplication.class, args); } } ================================================ FILE: 35.Spring-Security-Authentication/src/main/java/cc/mrbird/domain/MyUser.java ================================================ package cc.mrbird.domain; import java.io.Serializable; public class MyUser implements Serializable { private static final long serialVersionUID = 3497935890426858541L; private String userName; private String password; private boolean accountNonExpired = true; private boolean accountNonLocked= true; private boolean credentialsNonExpired= true; private boolean enabled= true; public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public boolean isAccountNonExpired() { return accountNonExpired; } public void setAccountNonExpired(boolean accountNonExpired) { this.accountNonExpired = accountNonExpired; } public boolean isAccountNonLocked() { return accountNonLocked; } public void setAccountNonLocked(boolean accountNonLocked) { this.accountNonLocked = accountNonLocked; } public boolean isCredentialsNonExpired() { return credentialsNonExpired; } public void setCredentialsNonExpired(boolean credentialsNonExpired) { this.credentialsNonExpired = credentialsNonExpired; } public boolean isEnabled() { return enabled; } public void setEnabled(boolean enabled) { this.enabled = enabled; } } ================================================ FILE: 35.Spring-Security-Authentication/src/main/java/cc/mrbird/handler/MyAuthenticationFailureHandler.java ================================================ package cc.mrbird.handler; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.stereotype.Component; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @Component public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler { @Autowired private ObjectMapper mapper; @Override public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException { response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value()); response.setContentType("application/json;charset=utf-8"); response.getWriter().write(mapper.writeValueAsString(exception.getMessage())); } } ================================================ FILE: 35.Spring-Security-Authentication/src/main/java/cc/mrbird/handler/MyAuthenticationSucessHandler.java ================================================ package cc.mrbird.handler; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.Authentication; import org.springframework.security.web.DefaultRedirectStrategy; import org.springframework.security.web.RedirectStrategy; import org.springframework.security.web.authentication.AuthenticationSuccessHandler; import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; import org.springframework.security.web.savedrequest.HttpSessionRequestCache; import org.springframework.security.web.savedrequest.RequestCache; import org.springframework.security.web.savedrequest.SavedRequest; import org.springframework.stereotype.Component; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @Component public class MyAuthenticationSucessHandler implements AuthenticationSuccessHandler { // private RequestCache requestCache = new HttpSessionRequestCache(); private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy(); // // @Autowired // private ObjectMapper mapper; @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException { // response.setContentType("application/json;charset=utf-8"); // response.getWriter().write(mapper.writeValueAsString(authentication)); // SavedRequest savedRequest = requestCache.getRequest(request, response); // System.out.println(savedRequest.getRedirectUrl()); // redirectStrategy.sendRedirect(request, response, savedRequest.getRedirectUrl()); redirectStrategy.sendRedirect(request, response, "/index"); } } ================================================ FILE: 35.Spring-Security-Authentication/src/main/java/cc/mrbird/security/browser/BrowserSecurityConfig.java ================================================ package cc.mrbird.security.browser; import cc.mrbird.handler.MyAuthenticationFailureHandler; import cc.mrbird.handler.MyAuthenticationSucessHandler; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; @Configuration public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private MyAuthenticationSucessHandler authenticationSucessHandler; @Autowired private MyAuthenticationFailureHandler authenticationFailureHandler; @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Override protected void configure(HttpSecurity http) throws Exception { http.formLogin() // 表单登录 // http.httpBasic() // HTTP Basic .loginPage("/authentication/require") // 登录跳转 URL .loginProcessingUrl("/login") // 处理表单登录 URL .successHandler(authenticationSucessHandler) // 处理登录成功 .failureHandler(authenticationFailureHandler) // 处理登录失败 .and() .authorizeRequests() // 授权配置 .antMatchers("/authentication/require", "/login.html").permitAll() // 登录跳转 URL 无需认证 .anyRequest() // 所有请求 .authenticated() // 都需要认证 .and().csrf().disable(); } } ================================================ FILE: 35.Spring-Security-Authentication/src/main/java/cc/mrbird/security/browser/UserDetailService.java ================================================ package cc.mrbird.security.browser; import cc.mrbird.domain.MyUser; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.crypto.password.PasswordEncoder; @Configuration public class UserDetailService implements UserDetailsService { @Autowired private PasswordEncoder passwordEncoder; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { // 模拟一个用户,替代数据库获取逻辑 MyUser user = new MyUser(); user.setUserName(username); user.setPassword(this.passwordEncoder.encode("123456")); // 输出加密后的密码 System.out.println(user.getPassword()); return new User(username, user.getPassword(), user.isEnabled(), user.isAccountNonExpired(), user.isCredentialsNonExpired(), user.isAccountNonLocked(), AuthorityUtils.commaSeparatedStringToAuthorityList("admin")); } } ================================================ FILE: 35.Spring-Security-Authentication/src/main/java/cc/mrbird/web/controller/BrowserSecurityController.java ================================================ package cc.mrbird.web.controller; import org.springframework.http.HttpStatus; import org.springframework.security.web.DefaultRedirectStrategy; import org.springframework.security.web.RedirectStrategy; import org.springframework.security.web.savedrequest.HttpSessionRequestCache; import org.springframework.security.web.savedrequest.RequestCache; import org.springframework.security.web.savedrequest.SavedRequest; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @author MrBird */ @RestController public class BrowserSecurityController { private RequestCache requestCache = new HttpSessionRequestCache(); private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy(); @GetMapping("/authentication/require") @ResponseStatus(HttpStatus.UNAUTHORIZED) public String requireAuthentication(HttpServletRequest request, HttpServletResponse response) throws IOException { SavedRequest savedRequest = requestCache.getRequest(request, response); if (savedRequest != null) { String targetUrl = savedRequest.getRedirectUrl(); if (StringUtils.endsWithIgnoreCase(targetUrl, ".html")) redirectStrategy.sendRedirect(request, response, "/login.html"); } return "访问的资源需要身份认证!"; } } ================================================ FILE: 35.Spring-Security-Authentication/src/main/java/cc/mrbird/web/controller/TestController.java ================================================ package cc.mrbird.web.controller; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class TestController { @GetMapping("hello") public String hello() { return "hello spring security"; } @GetMapping("index") public Object index(Authentication authentication) { // return SecurityContextHolder.getContext().getAuthentication(); return authentication; } } ================================================ FILE: 35.Spring-Security-Authentication/src/main/resources/application.yml ================================================ security: basic: enabled: true ================================================ FILE: 35.Spring-Security-Authentication/src/main/resources/resources/css/login.css ================================================ .login-page { width: 360px; padding: 8% 0 0; margin: auto; } .form { position: relative; z-index: 1; background: #ffffff; max-width: 360px; margin: 0 auto 100px; padding: 45px; text-align: center; box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.2), 0 5px 5px 0 rgba(0, 0, 0, 0.24); } .form input { outline: 0; background: #f2f2f2; width: 100%; border: 0; margin: 0 0 15px; padding: 15px; box-sizing: border-box; font-size: 14px; } .form button { text-transform: uppercase; outline: 0; background: #4caf50; width: 100%; border: 0; padding: 15px; color: #ffffff; font-size: 14px; -webkit-transition: all 0.3 ease; transition: all 0.3 ease; cursor: pointer; } .form button:hover, .form button:active, .form button:focus { background: #43a047; } .form .message { margin: 15px 0 0; color: #b3b3b3; font-size: 12px; } .form .message a { color: #4caf50; text-decoration: none; } .form .register-form { display: none; } .container { position: relative; z-index: 1; max-width: 300px; margin: 0 auto; } .container:before, .container:after { content: ""; display: block; clear: both; } .container .info { margin: 50px auto; text-align: center; } .container .info h1 { margin: 0 0 15px; padding: 0; font-size: 36px; font-weight: 300; color: #1a1a1a; } .container .info span { color: #4d4d4d; font-size: 12px; } .container .info span a { color: #000000; text-decoration: none; } .container .info span .fa { color: #ef3b3a; } body { background: #76b852; /* fallback for old browsers */ background: -webkit-linear-gradient(right, #76b852, #8dc26f); background: -moz-linear-gradient(right, #76b852, #8dc26f); background: -o-linear-gradient(right, #76b852, #8dc26f); background: linear-gradient(to left, #76b852, #8dc26f); font-family: Lato,"PingFang SC","Microsoft YaHei",sans-serif; } ================================================ FILE: 35.Spring-Security-Authentication/src/main/resources/resources/login.html ================================================ 登录 ================================================ FILE: 36.Spring-Security-ValidateCode/pom.xml ================================================ 4.0.0 cc.mrbird Security 1.0-SNAPSHOT jar Security Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.14.RELEASE UTF-8 UTF-8 1.8 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-security org.springframework.social spring-social-config org.apache.commons commons-lang3 3.7 org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 36.Spring-Security-ValidateCode/src/main/java/cc/mrbird/SecurityApplication.java ================================================ package cc.mrbird; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class SecurityApplication { public static void main(String[] args) { SpringApplication.run(SecurityApplication.class, args); } } ================================================ FILE: 36.Spring-Security-ValidateCode/src/main/java/cc/mrbird/domain/MyUser.java ================================================ package cc.mrbird.domain; import java.io.Serializable; public class MyUser implements Serializable { private static final long serialVersionUID = 3497935890426858541L; private String userName; private String password; private boolean accountNonExpired = true; private boolean accountNonLocked= true; private boolean credentialsNonExpired= true; private boolean enabled= true; public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public boolean isAccountNonExpired() { return accountNonExpired; } public void setAccountNonExpired(boolean accountNonExpired) { this.accountNonExpired = accountNonExpired; } public boolean isAccountNonLocked() { return accountNonLocked; } public void setAccountNonLocked(boolean accountNonLocked) { this.accountNonLocked = accountNonLocked; } public boolean isCredentialsNonExpired() { return credentialsNonExpired; } public void setCredentialsNonExpired(boolean credentialsNonExpired) { this.credentialsNonExpired = credentialsNonExpired; } public boolean isEnabled() { return enabled; } public void setEnabled(boolean enabled) { this.enabled = enabled; } } ================================================ FILE: 36.Spring-Security-ValidateCode/src/main/java/cc/mrbird/handler/MyAuthenticationFailureHandler.java ================================================ package cc.mrbird.handler; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.stereotype.Component; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @Component public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler { @Autowired private ObjectMapper mapper; @Override public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException { response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value()); response.setContentType("application/json;charset=utf-8"); response.getWriter().write(mapper.writeValueAsString(exception.getMessage())); } } ================================================ FILE: 36.Spring-Security-ValidateCode/src/main/java/cc/mrbird/handler/MyAuthenticationSucessHandler.java ================================================ package cc.mrbird.handler; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.Authentication; import org.springframework.security.web.DefaultRedirectStrategy; import org.springframework.security.web.RedirectStrategy; import org.springframework.security.web.authentication.AuthenticationSuccessHandler; import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; import org.springframework.security.web.savedrequest.HttpSessionRequestCache; import org.springframework.security.web.savedrequest.RequestCache; import org.springframework.security.web.savedrequest.SavedRequest; import org.springframework.stereotype.Component; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @Component public class MyAuthenticationSucessHandler implements AuthenticationSuccessHandler { // private RequestCache requestCache = new HttpSessionRequestCache(); private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy(); // // @Autowired // private ObjectMapper mapper; @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException { // response.setContentType("application/json;charset=utf-8"); // response.getWriter().write(mapper.writeValueAsString(authentication)); // SavedRequest savedRequest = requestCache.getRequest(request, response); // System.out.println(savedRequest.getRedirectUrl()); // redirectStrategy.sendRedirect(request, response, savedRequest.getRedirectUrl()); redirectStrategy.sendRedirect(request, response, "/index"); } } ================================================ FILE: 36.Spring-Security-ValidateCode/src/main/java/cc/mrbird/security/browser/BrowserSecurityConfig.java ================================================ package cc.mrbird.security.browser; import cc.mrbird.handler.MyAuthenticationFailureHandler; import cc.mrbird.handler.MyAuthenticationSucessHandler; import cc.mrbird.validate.code.ValidateCodeFilter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; @Configuration public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private MyAuthenticationSucessHandler authenticationSucessHandler; @Autowired private MyAuthenticationFailureHandler authenticationFailureHandler; @Autowired private ValidateCodeFilter validateCodeFilter; @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Override protected void configure(HttpSecurity http) throws Exception { http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class) // 添加验证码校验过滤器 .formLogin() // 表单登录 // http.httpBasic() // HTTP Basic .loginPage("/authentication/require") // 登录跳转 URL .loginProcessingUrl("/login") // 处理表单登录 URL .successHandler(authenticationSucessHandler) // 处理登录成功 .failureHandler(authenticationFailureHandler) // 处理登录失败 .and() .authorizeRequests() // 授权配置 .antMatchers("/authentication/require", "/login.html", "/code/image").permitAll() // 无需认证的请求路径 .anyRequest() // 所有请求 .authenticated() // 都需要认证 .and().csrf().disable(); } } ================================================ FILE: 36.Spring-Security-ValidateCode/src/main/java/cc/mrbird/security/browser/UserDetailService.java ================================================ package cc.mrbird.security.browser; import cc.mrbird.domain.MyUser; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.crypto.password.PasswordEncoder; @Configuration public class UserDetailService implements UserDetailsService { @Autowired private PasswordEncoder passwordEncoder; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { // 模拟一个用户,替代数据库获取逻辑 MyUser user = new MyUser(); user.setUserName(username); user.setPassword(this.passwordEncoder.encode("123456")); // 输出加密后的密码 System.out.println(user.getPassword()); return new User(username, user.getPassword(), user.isEnabled(), user.isAccountNonExpired(), user.isCredentialsNonExpired(), user.isAccountNonLocked(), AuthorityUtils.commaSeparatedStringToAuthorityList("admin")); } } ================================================ FILE: 36.Spring-Security-ValidateCode/src/main/java/cc/mrbird/validate/code/ImageCode.java ================================================ package cc.mrbird.validate.code; import java.awt.image.BufferedImage; import java.time.LocalDateTime; public class ImageCode { private BufferedImage image; private String code; private LocalDateTime expireTime; public ImageCode(BufferedImage image, String code, int expireIn) { this.image = image; this.code = code; this.expireTime = LocalDateTime.now().plusSeconds(expireIn); } public ImageCode(BufferedImage image, String code, LocalDateTime expireTime) { this.image = image; this.code = code; this.expireTime = expireTime; } boolean isExpire() { return LocalDateTime.now().isAfter(expireTime); } public BufferedImage getImage() { return image; } public void setImage(BufferedImage image) { this.image = image; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } public LocalDateTime getExpireTime() { return expireTime; } public void setExpireTime(LocalDateTime expireTime) { this.expireTime = expireTime; } } ================================================ FILE: 36.Spring-Security-ValidateCode/src/main/java/cc/mrbird/validate/code/ValidateCodeException.java ================================================ package cc.mrbird.validate.code; import org.springframework.security.core.AuthenticationException; public class ValidateCodeException extends AuthenticationException { private static final long serialVersionUID = 5022575393500654458L; ValidateCodeException(String message) { super(message); } } ================================================ FILE: 36.Spring-Security-ValidateCode/src/main/java/cc/mrbird/validate/code/ValidateCodeFilter.java ================================================ package cc.mrbird.validate.code; import cc.mrbird.web.controller.ValidateController; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.social.connect.web.HttpSessionSessionStrategy; import org.springframework.social.connect.web.SessionStrategy; import org.springframework.stereotype.Component; import org.springframework.web.bind.ServletRequestBindingException; import org.springframework.web.bind.ServletRequestUtils; import org.springframework.web.context.request.ServletWebRequest; import org.springframework.web.filter.OncePerRequestFilter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @Component public class ValidateCodeFilter extends OncePerRequestFilter { @Autowired private AuthenticationFailureHandler authenticationFailureHandler; private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy(); @Override protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException { if (StringUtils.equalsIgnoreCase("/login", httpServletRequest.getRequestURI()) && StringUtils.equalsIgnoreCase(httpServletRequest.getMethod(), "post")) { try { validateCode(new ServletWebRequest(httpServletRequest)); } catch (ValidateCodeException e) { authenticationFailureHandler.onAuthenticationFailure(httpServletRequest, httpServletResponse, e); return; } } filterChain.doFilter(httpServletRequest, httpServletResponse); } private void validateCode(ServletWebRequest servletWebRequest) throws ServletRequestBindingException { ImageCode codeInSession = (ImageCode) sessionStrategy.getAttribute(servletWebRequest, ValidateController.SESSION_KEY_IMAGE_CODE); String codeInRequest = ServletRequestUtils.getStringParameter(servletWebRequest.getRequest(), "imageCode"); if (StringUtils.isBlank(codeInRequest)) { throw new ValidateCodeException("验证码不能为空!"); } if (codeInSession == null) { throw new ValidateCodeException("验证码不存在!"); } if (codeInSession.isExpire()) { sessionStrategy.removeAttribute(servletWebRequest, ValidateController.SESSION_KEY_IMAGE_CODE); throw new ValidateCodeException("验证码已过期!"); } if (!StringUtils.equalsIgnoreCase(codeInSession.getCode(), codeInRequest)) { throw new ValidateCodeException("验证码不正确!"); } sessionStrategy.removeAttribute(servletWebRequest, ValidateController.SESSION_KEY_IMAGE_CODE); } } ================================================ FILE: 36.Spring-Security-ValidateCode/src/main/java/cc/mrbird/web/controller/BrowserSecurityController.java ================================================ package cc.mrbird.web.controller; import org.springframework.http.HttpStatus; import org.springframework.security.web.DefaultRedirectStrategy; import org.springframework.security.web.RedirectStrategy; import org.springframework.security.web.savedrequest.HttpSessionRequestCache; import org.springframework.security.web.savedrequest.RequestCache; import org.springframework.security.web.savedrequest.SavedRequest; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @author MrBird */ @RestController public class BrowserSecurityController { private RequestCache requestCache = new HttpSessionRequestCache(); private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy(); @GetMapping("/authentication/require") @ResponseStatus(HttpStatus.UNAUTHORIZED) public String requireAuthentication(HttpServletRequest request, HttpServletResponse response) throws IOException { SavedRequest savedRequest = requestCache.getRequest(request, response); if (savedRequest != null) { String targetUrl = savedRequest.getRedirectUrl(); if (StringUtils.endsWithIgnoreCase(targetUrl, ".html")) redirectStrategy.sendRedirect(request, response, "/login.html"); } return "访问的资源需要身份认证!"; } } ================================================ FILE: 36.Spring-Security-ValidateCode/src/main/java/cc/mrbird/web/controller/TestController.java ================================================ package cc.mrbird.web.controller; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class TestController { @GetMapping("hello") public String hello() { return "hello spring security"; } @GetMapping("index") public Object index(Authentication authentication) { // return SecurityContextHolder.getContext().getAuthentication(); return authentication; } } ================================================ FILE: 36.Spring-Security-ValidateCode/src/main/java/cc/mrbird/web/controller/ValidateController.java ================================================ package cc.mrbird.web.controller; import cc.mrbird.validate.code.ImageCode; import org.springframework.social.connect.web.HttpSessionSessionStrategy; import org.springframework.social.connect.web.SessionStrategy; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.context.request.ServletWebRequest; import javax.imageio.ImageIO; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.awt.*; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.Random; @RestController public class ValidateController { public final static String SESSION_KEY_IMAGE_CODE = "SESSION_KEY_IMAGE_CODE"; private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy(); @GetMapping("/code/image") public void createCode(HttpServletRequest request, HttpServletResponse response) throws IOException { ImageCode imageCode = createImageCode(); sessionStrategy.setAttribute(new ServletWebRequest(request), SESSION_KEY_IMAGE_CODE, imageCode); ImageIO.write(imageCode.getImage(), "jpeg", response.getOutputStream()); } private ImageCode createImageCode() { int width = 100; // 验证码图片宽度 int height = 36; // 验证码图片长度 int length = 4; // 验证码位数 int expireIn = 60; // 验证码有效时间 60s BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); Graphics g = image.getGraphics(); Random random = new Random(); g.setColor(getRandColor(200, 250)); g.fillRect(0, 0, width, height); g.setFont(new Font("Times New Roman", Font.ITALIC, 20)); g.setColor(getRandColor(160, 200)); for (int i = 0; i < 155; i++) { int x = random.nextInt(width); int y = random.nextInt(height); int xl = random.nextInt(12); int yl = random.nextInt(12); g.drawLine(x, y, x + xl, y + yl); } StringBuilder sRand = new StringBuilder(); for (int i = 0; i < length; i++) { String rand = String.valueOf(random.nextInt(10)); sRand.append(rand); g.setColor(new Color(20 + random.nextInt(110), 20 + random.nextInt(110), 20 + random.nextInt(110))); g.drawString(rand, 13 * i + 6, 16); } g.dispose(); return new ImageCode(image, sRand.toString(), expireIn); } private Color getRandColor(int fc, int bc) { Random random = new Random(); 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); } } ================================================ FILE: 36.Spring-Security-ValidateCode/src/main/resources/application.yml ================================================ security: basic: enabled: true ================================================ FILE: 36.Spring-Security-ValidateCode/src/main/resources/resources/css/login.css ================================================ .login-page { width: 360px; padding: 8% 0 0; margin: auto; } .form { position: relative; z-index: 1; background: #ffffff; max-width: 360px; margin: 0 auto 100px; padding: 45px; text-align: center; box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.2), 0 5px 5px 0 rgba(0, 0, 0, 0.24); } .form input { outline: 0; background: #f2f2f2; width: 100%; border: 0; margin: 0 0 15px; padding: 15px; box-sizing: border-box; font-size: 14px; } .form button { text-transform: uppercase; outline: 0; background: #4caf50; width: 100%; border: 0; padding: 15px; color: #ffffff; font-size: 14px; -webkit-transition: all 0.3 ease; transition: all 0.3 ease; cursor: pointer; } .form button:hover, .form button:active, .form button:focus { background: #43a047; } .form .message { margin: 15px 0 0; color: #b3b3b3; font-size: 12px; } .form .message a { color: #4caf50; text-decoration: none; } .form .register-form { display: none; } .container { position: relative; z-index: 1; max-width: 300px; margin: 0 auto; } .container:before, .container:after { content: ""; display: block; clear: both; } .container .info { margin: 50px auto; text-align: center; } .container .info h1 { margin: 0 0 15px; padding: 0; font-size: 36px; font-weight: 300; color: #1a1a1a; } .container .info span { color: #4d4d4d; font-size: 12px; } .container .info span a { color: #000000; text-decoration: none; } .container .info span .fa { color: #ef3b3a; } body { background: #76b852; /* fallback for old browsers */ background: -webkit-linear-gradient(right, #76b852, #8dc26f); background: -moz-linear-gradient(right, #76b852, #8dc26f); background: -o-linear-gradient(right, #76b852, #8dc26f); background: linear-gradient(to left, #76b852, #8dc26f); font-family: Lato,"PingFang SC","Microsoft YaHei",sans-serif; } ================================================ FILE: 36.Spring-Security-ValidateCode/src/main/resources/resources/login.html ================================================ 登录 ================================================ FILE: 37.Spring-Security-RememberMe/pom.xml ================================================ 4.0.0 cc.mrbird Security 1.0-SNAPSHOT jar Security Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.14.RELEASE UTF-8 UTF-8 1.8 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-security org.springframework.social spring-social-config org.springframework.boot spring-boot-starter-jdbc mysql mysql-connector-java org.apache.commons commons-lang3 3.7 org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 37.Spring-Security-RememberMe/src/main/java/cc/mrbird/SecurityApplication.java ================================================ package cc.mrbird; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class SecurityApplication { public static void main(String[] args) { SpringApplication.run(SecurityApplication.class, args); } } ================================================ FILE: 37.Spring-Security-RememberMe/src/main/java/cc/mrbird/domain/MyUser.java ================================================ package cc.mrbird.domain; import java.io.Serializable; public class MyUser implements Serializable { private static final long serialVersionUID = 3497935890426858541L; private String userName; private String password; private boolean accountNonExpired = true; private boolean accountNonLocked= true; private boolean credentialsNonExpired= true; private boolean enabled= true; public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public boolean isAccountNonExpired() { return accountNonExpired; } public void setAccountNonExpired(boolean accountNonExpired) { this.accountNonExpired = accountNonExpired; } public boolean isAccountNonLocked() { return accountNonLocked; } public void setAccountNonLocked(boolean accountNonLocked) { this.accountNonLocked = accountNonLocked; } public boolean isCredentialsNonExpired() { return credentialsNonExpired; } public void setCredentialsNonExpired(boolean credentialsNonExpired) { this.credentialsNonExpired = credentialsNonExpired; } public boolean isEnabled() { return enabled; } public void setEnabled(boolean enabled) { this.enabled = enabled; } } ================================================ FILE: 37.Spring-Security-RememberMe/src/main/java/cc/mrbird/handler/MyAuthenticationFailureHandler.java ================================================ package cc.mrbird.handler; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.stereotype.Component; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @Component public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler { @Autowired private ObjectMapper mapper; @Override public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException { response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value()); response.setContentType("application/json;charset=utf-8"); response.getWriter().write(mapper.writeValueAsString(exception.getMessage())); } } ================================================ FILE: 37.Spring-Security-RememberMe/src/main/java/cc/mrbird/handler/MyAuthenticationSucessHandler.java ================================================ package cc.mrbird.handler; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.Authentication; import org.springframework.security.web.DefaultRedirectStrategy; import org.springframework.security.web.RedirectStrategy; import org.springframework.security.web.authentication.AuthenticationSuccessHandler; import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; import org.springframework.security.web.savedrequest.HttpSessionRequestCache; import org.springframework.security.web.savedrequest.RequestCache; import org.springframework.security.web.savedrequest.SavedRequest; import org.springframework.stereotype.Component; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @Component public class MyAuthenticationSucessHandler implements AuthenticationSuccessHandler { // private RequestCache requestCache = new HttpSessionRequestCache(); private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy(); // // @Autowired // private ObjectMapper mapper; @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException { // response.setContentType("application/json;charset=utf-8"); // response.getWriter().write(mapper.writeValueAsString(authentication)); // SavedRequest savedRequest = requestCache.getRequest(request, response); // System.out.println(savedRequest.getRedirectUrl()); // redirectStrategy.sendRedirect(request, response, savedRequest.getRedirectUrl()); redirectStrategy.sendRedirect(request, response, "/index"); } } ================================================ FILE: 37.Spring-Security-RememberMe/src/main/java/cc/mrbird/security/browser/BrowserSecurityConfig.java ================================================ package cc.mrbird.security.browser; import cc.mrbird.handler.MyAuthenticationFailureHandler; import cc.mrbird.handler.MyAuthenticationSucessHandler; import cc.mrbird.validate.code.ValidateCodeFilter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl; import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository; import javax.sql.DataSource; @Configuration public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private MyAuthenticationSucessHandler authenticationSucessHandler; @Autowired private MyAuthenticationFailureHandler authenticationFailureHandler; @Autowired private ValidateCodeFilter validateCodeFilter; @Autowired private UserDetailService userDetailService; @Autowired private DataSource dataSource; @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Bean public PersistentTokenRepository persistentTokenRepository() { JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl(); jdbcTokenRepository.setDataSource(dataSource); jdbcTokenRepository.setCreateTableOnStartup(false); return jdbcTokenRepository; } @Override protected void configure(HttpSecurity http) throws Exception { http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class) // 添加验证码校验过滤器 .formLogin() // 表单登录 // http.httpBasic() // HTTP Basic .loginPage("/authentication/require") // 登录跳转 URL .loginProcessingUrl("/login") // 处理表单登录 URL .successHandler(authenticationSucessHandler) // 处理登录成功 .failureHandler(authenticationFailureHandler) // 处理登录失败 .and() .rememberMe() .tokenRepository(persistentTokenRepository()) // 配置 token 持久化仓库 .tokenValiditySeconds(3600) // remember 过期时间,单为秒 .userDetailsService(userDetailService) // 处理自动登录逻辑 .and() .authorizeRequests() // 授权配置 .antMatchers("/authentication/require", "/login.html", "/code/image").permitAll() // 无需认证的请求路径 .anyRequest() // 所有请求 .authenticated() // 都需要认证 .and() .csrf().disable(); } } ================================================ FILE: 37.Spring-Security-RememberMe/src/main/java/cc/mrbird/security/browser/UserDetailService.java ================================================ package cc.mrbird.security.browser; import cc.mrbird.domain.MyUser; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.crypto.password.PasswordEncoder; @Configuration public class UserDetailService implements UserDetailsService { @Autowired private PasswordEncoder passwordEncoder; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { // 模拟一个用户,替代数据库获取逻辑 MyUser user = new MyUser(); user.setUserName(username); user.setPassword(this.passwordEncoder.encode("123456")); // 输出加密后的密码 System.out.println(user.getPassword()); return new User(username, user.getPassword(), user.isEnabled(), user.isAccountNonExpired(), user.isCredentialsNonExpired(), user.isAccountNonLocked(), AuthorityUtils.commaSeparatedStringToAuthorityList("admin")); } } ================================================ FILE: 37.Spring-Security-RememberMe/src/main/java/cc/mrbird/validate/code/ImageCode.java ================================================ package cc.mrbird.validate.code; import java.awt.image.BufferedImage; import java.time.LocalDateTime; public class ImageCode { private BufferedImage image; private String code; private LocalDateTime expireTime; public ImageCode(BufferedImage image, String code, int expireIn) { this.image = image; this.code = code; this.expireTime = LocalDateTime.now().plusSeconds(expireIn); } public ImageCode(BufferedImage image, String code, LocalDateTime expireTime) { this.image = image; this.code = code; this.expireTime = expireTime; } boolean isExpire() { return LocalDateTime.now().isAfter(expireTime); } public BufferedImage getImage() { return image; } public void setImage(BufferedImage image) { this.image = image; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } public LocalDateTime getExpireTime() { return expireTime; } public void setExpireTime(LocalDateTime expireTime) { this.expireTime = expireTime; } } ================================================ FILE: 37.Spring-Security-RememberMe/src/main/java/cc/mrbird/validate/code/ValidateCodeException.java ================================================ package cc.mrbird.validate.code; import org.springframework.security.core.AuthenticationException; public class ValidateCodeException extends AuthenticationException { private static final long serialVersionUID = 5022575393500654458L; ValidateCodeException(String message) { super(message); } } ================================================ FILE: 37.Spring-Security-RememberMe/src/main/java/cc/mrbird/validate/code/ValidateCodeFilter.java ================================================ package cc.mrbird.validate.code; import cc.mrbird.web.controller.ValidateController; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.social.connect.web.HttpSessionSessionStrategy; import org.springframework.social.connect.web.SessionStrategy; import org.springframework.stereotype.Component; import org.springframework.web.bind.ServletRequestBindingException; import org.springframework.web.bind.ServletRequestUtils; import org.springframework.web.context.request.ServletWebRequest; import org.springframework.web.filter.OncePerRequestFilter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @Component public class ValidateCodeFilter extends OncePerRequestFilter { @Autowired private AuthenticationFailureHandler authenticationFailureHandler; private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy(); @Override protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException { if (StringUtils.equalsIgnoreCase("/login", httpServletRequest.getRequestURI()) && StringUtils.equalsIgnoreCase(httpServletRequest.getMethod(), "post")) { try { validateCode(new ServletWebRequest(httpServletRequest)); } catch (ValidateCodeException e) { authenticationFailureHandler.onAuthenticationFailure(httpServletRequest, httpServletResponse, e); return; } } filterChain.doFilter(httpServletRequest, httpServletResponse); } private void validateCode(ServletWebRequest servletWebRequest) throws ServletRequestBindingException { ImageCode codeInSession = (ImageCode) sessionStrategy.getAttribute(servletWebRequest, ValidateController.SESSION_KEY_IMAGE_CODE); String codeInRequest = ServletRequestUtils.getStringParameter(servletWebRequest.getRequest(), "imageCode"); if (StringUtils.isBlank(codeInRequest)) { throw new ValidateCodeException("验证码不能为空!"); } if (codeInSession == null) { throw new ValidateCodeException("验证码不存在!"); } if (codeInSession.isExpire()) { sessionStrategy.removeAttribute(servletWebRequest, ValidateController.SESSION_KEY_IMAGE_CODE); throw new ValidateCodeException("验证码已过期!"); } if (!StringUtils.equalsIgnoreCase(codeInSession.getCode(), codeInRequest)) { throw new ValidateCodeException("验证码不正确!"); } sessionStrategy.removeAttribute(servletWebRequest, ValidateController.SESSION_KEY_IMAGE_CODE); } } ================================================ FILE: 37.Spring-Security-RememberMe/src/main/java/cc/mrbird/web/controller/BrowserSecurityController.java ================================================ package cc.mrbird.web.controller; import org.springframework.http.HttpStatus; import org.springframework.security.web.DefaultRedirectStrategy; import org.springframework.security.web.RedirectStrategy; import org.springframework.security.web.savedrequest.HttpSessionRequestCache; import org.springframework.security.web.savedrequest.RequestCache; import org.springframework.security.web.savedrequest.SavedRequest; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @author MrBird */ @RestController public class BrowserSecurityController { private RequestCache requestCache = new HttpSessionRequestCache(); private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy(); @GetMapping("/authentication/require") @ResponseStatus(HttpStatus.UNAUTHORIZED) public String requireAuthentication(HttpServletRequest request, HttpServletResponse response) throws IOException { SavedRequest savedRequest = requestCache.getRequest(request, response); if (savedRequest != null) { String targetUrl = savedRequest.getRedirectUrl(); if (StringUtils.endsWithIgnoreCase(targetUrl, ".html")) redirectStrategy.sendRedirect(request, response, "/login.html"); } return "访问的资源需要身份认证!"; } } ================================================ FILE: 37.Spring-Security-RememberMe/src/main/java/cc/mrbird/web/controller/TestController.java ================================================ package cc.mrbird.web.controller; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class TestController { @GetMapping("hello") public String hello() { return "hello spring security"; } @GetMapping("index") public Object index(Authentication authentication) { // return SecurityContextHolder.getContext().getAuthentication(); return authentication; } } ================================================ FILE: 37.Spring-Security-RememberMe/src/main/java/cc/mrbird/web/controller/ValidateController.java ================================================ package cc.mrbird.web.controller; import cc.mrbird.validate.code.ImageCode; import org.springframework.social.connect.web.HttpSessionSessionStrategy; import org.springframework.social.connect.web.SessionStrategy; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.context.request.ServletWebRequest; import javax.imageio.ImageIO; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.awt.*; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.Random; @RestController public class ValidateController { public final static String SESSION_KEY_IMAGE_CODE = "SESSION_KEY_IMAGE_CODE"; private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy(); @GetMapping("/code/image") public void createCode(HttpServletRequest request, HttpServletResponse response) throws IOException { ImageCode imageCode = createImageCode(); sessionStrategy.setAttribute(new ServletWebRequest(request), SESSION_KEY_IMAGE_CODE, imageCode); ImageIO.write(imageCode.getImage(), "jpeg", response.getOutputStream()); } private ImageCode createImageCode() { int width = 100; // 验证码图片宽度 int height = 36; // 验证码图片长度 int length = 4; // 验证码位数 int expireIn = 60; // 验证码有效时间 60s BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); Graphics g = image.getGraphics(); Random random = new Random(); g.setColor(getRandColor(200, 250)); g.fillRect(0, 0, width, height); g.setFont(new Font("Times New Roman", Font.ITALIC, 20)); g.setColor(getRandColor(160, 200)); for (int i = 0; i < 155; i++) { int x = random.nextInt(width); int y = random.nextInt(height); int xl = random.nextInt(12); int yl = random.nextInt(12); g.drawLine(x, y, x + xl, y + yl); } StringBuilder sRand = new StringBuilder(); for (int i = 0; i < length; i++) { String rand = String.valueOf(random.nextInt(10)); sRand.append(rand); g.setColor(new Color(20 + random.nextInt(110), 20 + random.nextInt(110), 20 + random.nextInt(110))); g.drawString(rand, 13 * i + 6, 16); } g.dispose(); return new ImageCode(image, sRand.toString(), expireIn); } private Color getRandColor(int fc, int bc) { Random random = new Random(); 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); } } ================================================ FILE: 37.Spring-Security-RememberMe/src/main/resources/application.yml ================================================ security: basic: enabled: true spring: datasource: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://127.0.0.1:3306/security?useUnicode=yes&characterEncoding=UTF-8&useSSL=false username: root password: 123456 ================================================ FILE: 37.Spring-Security-RememberMe/src/main/resources/resources/css/login.css ================================================ .login-page { width: 360px; padding: 8% 0 0; margin: auto; } .form { position: relative; z-index: 1; background: #ffffff; max-width: 360px; margin: 0 auto 100px; padding: 45px; text-align: center; box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.2), 0 5px 5px 0 rgba(0, 0, 0, 0.24); } .form input { outline: 0; background: #f2f2f2; width: 100%; border: 0; margin: 0 0 15px; padding: 15px; box-sizing: border-box; font-size: 14px; } .form button { text-transform: uppercase; outline: 0; background: #4caf50; width: 100%; border: 0; padding: 15px; color: #ffffff; font-size: 14px; -webkit-transition: all 0.3 ease; transition: all 0.3 ease; cursor: pointer; } .form button:hover, .form button:active, .form button:focus { background: #43a047; } .form .message { margin: 15px 0 0; color: #b3b3b3; font-size: 12px; } .form .message a { color: #4caf50; text-decoration: none; } .form .register-form { display: none; } .container { position: relative; z-index: 1; max-width: 300px; margin: 0 auto; } .container:before, .container:after { content: ""; display: block; clear: both; } .container .info { margin: 50px auto; text-align: center; } .container .info h1 { margin: 0 0 15px; padding: 0; font-size: 36px; font-weight: 300; color: #1a1a1a; } .container .info span { color: #4d4d4d; font-size: 12px; } .container .info span a { color: #000000; text-decoration: none; } .container .info span .fa { color: #ef3b3a; } body { background: #76b852; /* fallback for old browsers */ background: -webkit-linear-gradient(right, #76b852, #8dc26f); background: -moz-linear-gradient(right, #76b852, #8dc26f); background: -o-linear-gradient(right, #76b852, #8dc26f); background: linear-gradient(to left, #76b852, #8dc26f); font-family: Lato,"PingFang SC","Microsoft YaHei",sans-serif; } ================================================ FILE: 37.Spring-Security-RememberMe/src/main/resources/resources/login.html ================================================ 登录 ================================================ FILE: 38.Spring-Security-SmsCode/pom.xml ================================================ 4.0.0 cc.mrbird Security 1.0-SNAPSHOT jar Security Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.14.RELEASE UTF-8 UTF-8 1.8 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-security org.springframework.social spring-social-config org.apache.commons commons-lang3 3.7 org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 38.Spring-Security-SmsCode/src/main/java/cc/mrbird/SecurityApplication.java ================================================ package cc.mrbird; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class SecurityApplication { public static void main(String[] args) { SpringApplication.run(SecurityApplication.class, args); } } ================================================ FILE: 38.Spring-Security-SmsCode/src/main/java/cc/mrbird/domain/MyUser.java ================================================ package cc.mrbird.domain; import java.io.Serializable; public class MyUser implements Serializable { private static final long serialVersionUID = 3497935890426858541L; private String userName; private String password; private boolean accountNonExpired = true; private boolean accountNonLocked= true; private boolean credentialsNonExpired= true; private boolean enabled= true; public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public boolean isAccountNonExpired() { return accountNonExpired; } public void setAccountNonExpired(boolean accountNonExpired) { this.accountNonExpired = accountNonExpired; } public boolean isAccountNonLocked() { return accountNonLocked; } public void setAccountNonLocked(boolean accountNonLocked) { this.accountNonLocked = accountNonLocked; } public boolean isCredentialsNonExpired() { return credentialsNonExpired; } public void setCredentialsNonExpired(boolean credentialsNonExpired) { this.credentialsNonExpired = credentialsNonExpired; } public boolean isEnabled() { return enabled; } public void setEnabled(boolean enabled) { this.enabled = enabled; } } ================================================ FILE: 38.Spring-Security-SmsCode/src/main/java/cc/mrbird/handler/MyAuthenticationFailureHandler.java ================================================ package cc.mrbird.handler; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.stereotype.Component; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @Component public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler { @Autowired private ObjectMapper mapper; @Override public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException { response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value()); response.setContentType("application/json;charset=utf-8"); response.getWriter().write(mapper.writeValueAsString(exception.getMessage())); } } ================================================ FILE: 38.Spring-Security-SmsCode/src/main/java/cc/mrbird/handler/MyAuthenticationSucessHandler.java ================================================ package cc.mrbird.handler; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.Authentication; import org.springframework.security.web.DefaultRedirectStrategy; import org.springframework.security.web.RedirectStrategy; import org.springframework.security.web.authentication.AuthenticationSuccessHandler; import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; import org.springframework.security.web.savedrequest.HttpSessionRequestCache; import org.springframework.security.web.savedrequest.RequestCache; import org.springframework.security.web.savedrequest.SavedRequest; import org.springframework.stereotype.Component; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @Component public class MyAuthenticationSucessHandler implements AuthenticationSuccessHandler { // private RequestCache requestCache = new HttpSessionRequestCache(); private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy(); // // @Autowired // private ObjectMapper mapper; @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException { // response.setContentType("application/json;charset=utf-8"); // response.getWriter().write(mapper.writeValueAsString(authentication)); // SavedRequest savedRequest = requestCache.getRequest(request, response); // System.out.println(savedRequest.getRedirectUrl()); // redirectStrategy.sendRedirect(request, response, savedRequest.getRedirectUrl()); redirectStrategy.sendRedirect(request, response, "/index"); } } ================================================ FILE: 38.Spring-Security-SmsCode/src/main/java/cc/mrbird/security/browser/BrowserSecurityConfig.java ================================================ package cc.mrbird.security.browser; import cc.mrbird.handler.MyAuthenticationFailureHandler; import cc.mrbird.handler.MyAuthenticationSucessHandler; import cc.mrbird.validate.code.ValidateCodeFilter; import cc.mrbird.validate.smscode.SmsAuthenticationConfig; import cc.mrbird.validate.smscode.SmsAuthenticationFilter; import cc.mrbird.validate.smscode.SmsCodeFilter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; @Configuration public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private MyAuthenticationSucessHandler authenticationSucessHandler; @Autowired private MyAuthenticationFailureHandler authenticationFailureHandler; @Autowired private ValidateCodeFilter validateCodeFilter; @Autowired private SmsCodeFilter smsCodeFilter; @Autowired private SmsAuthenticationConfig smsAuthenticationConfig; @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Override protected void configure(HttpSecurity http) throws Exception { http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class) // 添加验证码校验过滤器 .addFilterBefore(smsCodeFilter,UsernamePasswordAuthenticationFilter.class) // 添加短信验证码校验过滤器 .formLogin() // 表单登录 // http.httpBasic() // HTTP Basic .loginPage("/authentication/require") // 登录跳转 URL .loginProcessingUrl("/login") // 处理表单登录 URL .successHandler(authenticationSucessHandler) // 处理登录成功 .failureHandler(authenticationFailureHandler) // 处理登录失败 .and() .authorizeRequests() // 授权配置 .antMatchers("/authentication/require", "/login.html", "/code/image","/code/sms").permitAll() // 无需认证的请求路径 .anyRequest() // 所有请求 .authenticated() // 都需要认证 .and() .csrf().disable() .apply(smsAuthenticationConfig); // 将短信验证码认证配置加到 Spring Security 中 } } ================================================ FILE: 38.Spring-Security-SmsCode/src/main/java/cc/mrbird/security/browser/UserDetailService.java ================================================ package cc.mrbird.security.browser; import cc.mrbird.domain.MyUser; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.crypto.password.PasswordEncoder; @Configuration public class UserDetailService implements UserDetailsService { @Autowired private PasswordEncoder passwordEncoder; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { // 模拟一个用户,替代数据库获取逻辑 MyUser user = new MyUser(); user.setUserName(username); user.setPassword(this.passwordEncoder.encode("123456")); // 输出加密后的密码 System.out.println(user.getPassword()); return new User(username, user.getPassword(), user.isEnabled(), user.isAccountNonExpired(), user.isCredentialsNonExpired(), user.isAccountNonLocked(), AuthorityUtils.commaSeparatedStringToAuthorityList("admin")); } } ================================================ FILE: 38.Spring-Security-SmsCode/src/main/java/cc/mrbird/validate/code/ImageCode.java ================================================ package cc.mrbird.validate.code; import java.awt.image.BufferedImage; import java.time.LocalDateTime; public class ImageCode { private BufferedImage image; private String code; private LocalDateTime expireTime; public ImageCode(BufferedImage image, String code, int expireIn) { this.image = image; this.code = code; this.expireTime = LocalDateTime.now().plusSeconds(expireIn); } public ImageCode(BufferedImage image, String code, LocalDateTime expireTime) { this.image = image; this.code = code; this.expireTime = expireTime; } boolean isExpire() { return LocalDateTime.now().isAfter(expireTime); } public BufferedImage getImage() { return image; } public void setImage(BufferedImage image) { this.image = image; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } public LocalDateTime getExpireTime() { return expireTime; } public void setExpireTime(LocalDateTime expireTime) { this.expireTime = expireTime; } } ================================================ FILE: 38.Spring-Security-SmsCode/src/main/java/cc/mrbird/validate/code/ValidateCodeException.java ================================================ package cc.mrbird.validate.code; import org.springframework.security.core.AuthenticationException; public class ValidateCodeException extends AuthenticationException { private static final long serialVersionUID = 5022575393500654458L; public ValidateCodeException(String message) { super(message); } } ================================================ FILE: 38.Spring-Security-SmsCode/src/main/java/cc/mrbird/validate/code/ValidateCodeFilter.java ================================================ package cc.mrbird.validate.code; import cc.mrbird.web.controller.ValidateController; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.social.connect.web.HttpSessionSessionStrategy; import org.springframework.social.connect.web.SessionStrategy; import org.springframework.stereotype.Component; import org.springframework.web.bind.ServletRequestBindingException; import org.springframework.web.bind.ServletRequestUtils; import org.springframework.web.context.request.ServletWebRequest; import org.springframework.web.filter.OncePerRequestFilter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @Component public class ValidateCodeFilter extends OncePerRequestFilter { @Autowired private AuthenticationFailureHandler authenticationFailureHandler; private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy(); @Override protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException { if (StringUtils.equalsIgnoreCase("/login", httpServletRequest.getRequestURI()) && StringUtils.equalsIgnoreCase(httpServletRequest.getMethod(), "post")) { try { validateCode(new ServletWebRequest(httpServletRequest)); } catch (ValidateCodeException e) { authenticationFailureHandler.onAuthenticationFailure(httpServletRequest, httpServletResponse, e); return; } } filterChain.doFilter(httpServletRequest, httpServletResponse); } private void validateCode(ServletWebRequest servletWebRequest) throws ServletRequestBindingException { ImageCode codeInSession = (ImageCode) sessionStrategy.getAttribute(servletWebRequest, ValidateController.SESSION_KEY_IMAGE_CODE); String codeInRequest = ServletRequestUtils.getStringParameter(servletWebRequest.getRequest(), "imageCode"); if (StringUtils.isBlank(codeInRequest)) { throw new ValidateCodeException("验证码不能为空!"); } if (codeInSession == null) { throw new ValidateCodeException("验证码不存在!"); } if (codeInSession.isExpire()) { sessionStrategy.removeAttribute(servletWebRequest, ValidateController.SESSION_KEY_IMAGE_CODE); throw new ValidateCodeException("验证码已过期!"); } if (!StringUtils.equalsIgnoreCase(codeInSession.getCode(), codeInRequest)) { throw new ValidateCodeException("验证码不正确!"); } sessionStrategy.removeAttribute(servletWebRequest, ValidateController.SESSION_KEY_IMAGE_CODE); } } ================================================ FILE: 38.Spring-Security-SmsCode/src/main/java/cc/mrbird/validate/smscode/SmsAuthenticationConfig.java ================================================ package cc.mrbird.validate.smscode; import cc.mrbird.security.browser.UserDetailService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.SecurityConfigurerAdapter; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.web.DefaultSecurityFilterChain; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.security.web.authentication.AuthenticationSuccessHandler; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.stereotype.Component; @Component public class SmsAuthenticationConfig extends SecurityConfigurerAdapter { @Autowired private AuthenticationSuccessHandler authenticationSuccessHandler; @Autowired private AuthenticationFailureHandler authenticationFailureHandler; @Autowired private UserDetailService userDetailService; @Override public void configure(HttpSecurity http) throws Exception { SmsAuthenticationFilter smsAuthenticationFilter = new SmsAuthenticationFilter(); smsAuthenticationFilter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class)); smsAuthenticationFilter.setAuthenticationSuccessHandler(authenticationSuccessHandler); smsAuthenticationFilter.setAuthenticationFailureHandler(authenticationFailureHandler); SmsAuthenticationProvider smsAuthenticationProvider = new SmsAuthenticationProvider(); smsAuthenticationProvider.setUserDetailService(userDetailService); http.authenticationProvider(smsAuthenticationProvider) .addFilterAfter(smsAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); } } ================================================ FILE: 38.Spring-Security-SmsCode/src/main/java/cc/mrbird/validate/smscode/SmsAuthenticationFilter.java ================================================ package cc.mrbird.validate.smscode; import org.springframework.security.authentication.AuthenticationServiceException; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.util.Assert; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class SmsAuthenticationFilter extends AbstractAuthenticationProcessingFilter { public static final String MOBILE_KEY = "mobile"; private String mobileParameter = MOBILE_KEY; private boolean postOnly = true; public SmsAuthenticationFilter() { super(new AntPathRequestMatcher("/login/mobile", "POST")); } public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { if (postOnly && !request.getMethod().equals("POST")) { throw new AuthenticationServiceException( "Authentication method not supported: " + request.getMethod()); } String mobile = obtainMobile(request); if (mobile == null) { mobile = ""; } mobile = mobile.trim(); SmsAuthenticationToken authRequest = new SmsAuthenticationToken(mobile); setDetails(request, authRequest); return this.getAuthenticationManager().authenticate(authRequest); } protected String obtainMobile(HttpServletRequest request) { return request.getParameter(mobileParameter); } protected void setDetails(HttpServletRequest request, SmsAuthenticationToken authRequest) { authRequest.setDetails(authenticationDetailsSource.buildDetails(request)); } public void setMobileParameter(String mobileParameter) { Assert.hasText(mobileParameter, "mobile parameter must not be empty or null"); this.mobileParameter = mobileParameter; } public void setPostOnly(boolean postOnly) { this.postOnly = postOnly; } public final String getMobileParameter() { return mobileParameter; } } ================================================ FILE: 38.Spring-Security-SmsCode/src/main/java/cc/mrbird/validate/smscode/SmsAuthenticationProvider.java ================================================ package cc.mrbird.validate.smscode; import cc.mrbird.security.browser.UserDetailService; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.InternalAuthenticationServiceException; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.userdetails.UserDetails; public class SmsAuthenticationProvider implements AuthenticationProvider { private UserDetailService userDetailService; @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { SmsAuthenticationToken authenticationToken = (SmsAuthenticationToken) authentication; UserDetails userDetails = userDetailService.loadUserByUsername((String) authenticationToken.getPrincipal()); if (userDetails == null) throw new InternalAuthenticationServiceException("未找到与该手机号对应的用户"); SmsAuthenticationToken authenticationResult = new SmsAuthenticationToken(userDetails, userDetails.getAuthorities()); authenticationResult.setDetails(authenticationToken.getDetails()); return authenticationResult; } @Override public boolean supports(Class aClass) { return SmsAuthenticationToken.class.isAssignableFrom(aClass); } public UserDetailService getUserDetailService() { return userDetailService; } public void setUserDetailService(UserDetailService userDetailService) { this.userDetailService = userDetailService; } } ================================================ FILE: 38.Spring-Security-SmsCode/src/main/java/cc/mrbird/validate/smscode/SmsAuthenticationToken.java ================================================ package cc.mrbird.validate.smscode; import org.springframework.security.authentication.AbstractAuthenticationToken; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.SpringSecurityCoreVersion; import java.util.Collection; public class SmsAuthenticationToken extends AbstractAuthenticationToken { private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID; private final Object principal; public SmsAuthenticationToken(String mobile) { super(null); this.principal = mobile; setAuthenticated(false); } public SmsAuthenticationToken(Object principal, Collection authorities) { super(authorities); this.principal = principal; super.setAuthenticated(true); // must use super, as we override } @Override public Object getCredentials() { return null; } public Object getPrincipal() { return this.principal; } public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException { if (isAuthenticated) { throw new IllegalArgumentException( "Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead"); } super.setAuthenticated(false); } @Override public void eraseCredentials() { super.eraseCredentials(); } } ================================================ FILE: 38.Spring-Security-SmsCode/src/main/java/cc/mrbird/validate/smscode/SmsCode.java ================================================ package cc.mrbird.validate.smscode; import java.time.LocalDateTime; public class SmsCode { private String code; private LocalDateTime expireTime; public SmsCode(String code, int expireIn) { this.code = code; this.expireTime = LocalDateTime.now().plusSeconds(expireIn); } public SmsCode(String code, LocalDateTime expireTime) { this.code = code; this.expireTime = expireTime; } boolean isExpire() { return LocalDateTime.now().isAfter(expireTime); } public String getCode() { return code; } public void setCode(String code) { this.code = code; } public LocalDateTime getExpireTime() { return expireTime; } public void setExpireTime(LocalDateTime expireTime) { this.expireTime = expireTime; } } ================================================ FILE: 38.Spring-Security-SmsCode/src/main/java/cc/mrbird/validate/smscode/SmsCodeFilter.java ================================================ package cc.mrbird.validate.smscode; import cc.mrbird.validate.code.ValidateCodeException; import cc.mrbird.web.controller.ValidateController; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.social.connect.web.HttpSessionSessionStrategy; import org.springframework.social.connect.web.SessionStrategy; import org.springframework.stereotype.Component; import org.springframework.web.bind.ServletRequestBindingException; import org.springframework.web.bind.ServletRequestUtils; import org.springframework.web.context.request.ServletWebRequest; import org.springframework.web.filter.OncePerRequestFilter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @Component public class SmsCodeFilter extends OncePerRequestFilter { @Autowired private AuthenticationFailureHandler authenticationFailureHandler; private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy(); @Override protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException { if (StringUtils.equalsIgnoreCase("/login/mobile", httpServletRequest.getRequestURI()) && StringUtils.equalsIgnoreCase(httpServletRequest.getMethod(), "post")) { try { validateCode(new ServletWebRequest(httpServletRequest)); } catch (ValidateCodeException e) { authenticationFailureHandler.onAuthenticationFailure(httpServletRequest, httpServletResponse, e); return; } } filterChain.doFilter(httpServletRequest, httpServletResponse); } private void validateCode(ServletWebRequest servletWebRequest) throws ServletRequestBindingException { String smsCodeInRequest = ServletRequestUtils.getStringParameter(servletWebRequest.getRequest(), "smsCode"); String mobileInRequest = ServletRequestUtils.getStringParameter(servletWebRequest.getRequest(), "smsCode"); SmsCode codeInSession = (SmsCode) sessionStrategy.getAttribute(servletWebRequest, ValidateController.SESSION_KEY_SMS_CODE + mobileInRequest); if (StringUtils.isBlank(smsCodeInRequest)) { throw new ValidateCodeException("验证码不能为空!"); } if (codeInSession == null) { throw new ValidateCodeException("验证码不存在!"); } if (codeInSession.isExpire()) { sessionStrategy.removeAttribute(servletWebRequest, ValidateController.SESSION_KEY_IMAGE_CODE); throw new ValidateCodeException("验证码已过期!"); } if (!StringUtils.equalsIgnoreCase(codeInSession.getCode(), smsCodeInRequest)) { throw new ValidateCodeException("验证码不正确!"); } sessionStrategy.removeAttribute(servletWebRequest, ValidateController.SESSION_KEY_IMAGE_CODE); } } ================================================ FILE: 38.Spring-Security-SmsCode/src/main/java/cc/mrbird/web/controller/BrowserSecurityController.java ================================================ package cc.mrbird.web.controller; import org.springframework.http.HttpStatus; import org.springframework.security.web.DefaultRedirectStrategy; import org.springframework.security.web.RedirectStrategy; import org.springframework.security.web.savedrequest.HttpSessionRequestCache; import org.springframework.security.web.savedrequest.RequestCache; import org.springframework.security.web.savedrequest.SavedRequest; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @author MrBird */ @RestController public class BrowserSecurityController { private RequestCache requestCache = new HttpSessionRequestCache(); private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy(); @GetMapping("/authentication/require") @ResponseStatus(HttpStatus.UNAUTHORIZED) public String requireAuthentication(HttpServletRequest request, HttpServletResponse response) throws IOException { SavedRequest savedRequest = requestCache.getRequest(request, response); if (savedRequest != null) { String targetUrl = savedRequest.getRedirectUrl(); if (StringUtils.endsWithIgnoreCase(targetUrl, ".html")) redirectStrategy.sendRedirect(request, response, "/login.html"); } return "访问的资源需要身份认证!"; } } ================================================ FILE: 38.Spring-Security-SmsCode/src/main/java/cc/mrbird/web/controller/TestController.java ================================================ package cc.mrbird.web.controller; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class TestController { @GetMapping("hello") public String hello() { return "hello spring security"; } @GetMapping("index") public Object index(Authentication authentication) { // return SecurityContextHolder.getContext().getAuthentication(); return authentication; } } ================================================ FILE: 38.Spring-Security-SmsCode/src/main/java/cc/mrbird/web/controller/ValidateController.java ================================================ package cc.mrbird.web.controller; import cc.mrbird.validate.code.ImageCode; import cc.mrbird.validate.smscode.SmsCode; import org.apache.commons.lang3.RandomStringUtils; import org.springframework.social.connect.web.HttpSessionSessionStrategy; import org.springframework.social.connect.web.SessionStrategy; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.context.request.ServletWebRequest; import javax.imageio.ImageIO; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.awt.*; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.Random; @RestController public class ValidateController { public final static String SESSION_KEY_IMAGE_CODE = "SESSION_KEY_IMAGE_CODE"; public final static String SESSION_KEY_SMS_CODE = "SESSION_KEY_SMS_CODE"; private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy(); @GetMapping("/code/image") public void createCode(HttpServletRequest request, HttpServletResponse response) throws IOException { ImageCode imageCode = createImageCode(); sessionStrategy.setAttribute(new ServletWebRequest(request), SESSION_KEY_IMAGE_CODE, imageCode); ImageIO.write(imageCode.getImage(), "jpeg", response.getOutputStream()); } @GetMapping("/code/sms") public void createSmsCode(HttpServletRequest request, HttpServletResponse response, String mobile) { SmsCode smsCode = createSMSCode(); sessionStrategy.setAttribute(new ServletWebRequest(request), SESSION_KEY_SMS_CODE + mobile, smsCode); // 输出验证码到控制台代替短信发送服务 System.out.println("您的登录验证码为:" + smsCode.getCode() + ",有效时间为60秒"); } private SmsCode createSMSCode() { String code = RandomStringUtils.randomNumeric(6); return new SmsCode(code, 60); } private ImageCode createImageCode() { int width = 100; // 验证码图片宽度 int height = 36; // 验证码图片长度 int length = 4; // 验证码位数 int expireIn = 60; // 验证码有效时间 60s BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); Graphics g = image.getGraphics(); Random random = new Random(); g.setColor(getRandColor(200, 250)); g.fillRect(0, 0, width, height); g.setFont(new Font("Times New Roman", Font.ITALIC, 20)); g.setColor(getRandColor(160, 200)); for (int i = 0; i < 155; i++) { int x = random.nextInt(width); int y = random.nextInt(height); int xl = random.nextInt(12); int yl = random.nextInt(12); g.drawLine(x, y, x + xl, y + yl); } StringBuilder sRand = new StringBuilder(); for (int i = 0; i < length; i++) { String rand = String.valueOf(random.nextInt(10)); sRand.append(rand); g.setColor(new Color(20 + random.nextInt(110), 20 + random.nextInt(110), 20 + random.nextInt(110))); g.drawString(rand, 13 * i + 6, 16); } g.dispose(); return new ImageCode(image, sRand.toString(), expireIn); } private Color getRandColor(int fc, int bc) { Random random = new Random(); 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); } } ================================================ FILE: 38.Spring-Security-SmsCode/src/main/resources/application.yml ================================================ security: basic: enabled: true ================================================ FILE: 38.Spring-Security-SmsCode/src/main/resources/resources/css/login.css ================================================ .login-page { width: 360px; padding: 8% 0 0; margin: auto; } .form { position: relative; z-index: 1; background: #ffffff; max-width: 360px; margin: 0 auto 100px; padding: 45px; text-align: center; box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.2), 0 5px 5px 0 rgba(0, 0, 0, 0.24); } .form input { outline: 0; background: #f2f2f2; width: 100%; border: 0; margin: 0 0 15px; padding: 15px; box-sizing: border-box; font-size: 14px; } .form button { text-transform: uppercase; outline: 0; background: #4caf50; width: 100%; border: 0; padding: 15px; color: #ffffff; font-size: 14px; -webkit-transition: all 0.3 ease; transition: all 0.3 ease; cursor: pointer; } .form button:hover, .form button:active, .form button:focus { background: #43a047; } .form .message { margin: 15px 0 0; color: #b3b3b3; font-size: 12px; } .form .message a { color: #4caf50; text-decoration: none; } .form .register-form { display: none; } .container { position: relative; z-index: 1; max-width: 300px; margin: 0 auto; } .container:before, .container:after { content: ""; display: block; clear: both; } .container .info { margin: 50px auto; text-align: center; } .container .info h1 { margin: 0 0 15px; padding: 0; font-size: 36px; font-weight: 300; color: #1a1a1a; } .container .info span { color: #4d4d4d; font-size: 12px; } .container .info span a { color: #000000; text-decoration: none; } .container .info span .fa { color: #ef3b3a; } body { background: #76b852; /* fallback for old browsers */ background: -webkit-linear-gradient(right, #76b852, #8dc26f); background: -moz-linear-gradient(right, #76b852, #8dc26f); background: -o-linear-gradient(right, #76b852, #8dc26f); background: linear-gradient(to left, #76b852, #8dc26f); font-family: Lato,"PingFang SC","Microsoft YaHei",sans-serif; } ================================================ FILE: 38.Spring-Security-SmsCode/src/main/resources/resources/login.html ================================================ 登录 ================================================ FILE: 39.Spring-Cloud-Zuul-Router/Eureka-Client/pom.xml ================================================ 4.0.0 com.example Eureka-Client 0.0.1-SNAPSHOT jar Eureka-Client Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.13.RELEASE UTF-8 UTF-8 1.8 org.springframework.cloud spring-cloud-dependencies Edgware.SR3 pom import org.springframework.cloud spring-cloud-starter-eureka org.springframework.boot spring-boot-starter org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 39.Spring-Cloud-Zuul-Router/Eureka-Client/src/main/java/com/example/demo/DemoApplication.java ================================================ package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; @EnableDiscoveryClient @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ================================================ FILE: 39.Spring-Cloud-Zuul-Router/Eureka-Client/src/main/java/com/example/demo/controller/TestController.java ================================================ package com.example.demo.controller; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class TestController { private Logger log = LoggerFactory.getLogger(this.getClass()); @Autowired private DiscoveryClient client; @GetMapping("/info") public String info() { @SuppressWarnings("deprecation") ServiceInstance instance = client.getLocalServiceInstance(); String info = "host:" + instance.getHost() + ",service_id:" + instance.getServiceId(); log.info(info); return info; } @GetMapping("/hello") public String hello() { return "hello world"; } } ================================================ FILE: 39.Spring-Cloud-Zuul-Router/Eureka-Client/src/main/java/com/example/demo/controller/UserController.java ================================================ package com.example.demo.controller; import com.example.demo.domain.User; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.*; import java.util.ArrayList; import java.util.List; @RestController @RequestMapping("user") public class UserController { private Logger log = LoggerFactory.getLogger(this.getClass()); @GetMapping("/{id:\\d+}") public User get(@PathVariable Long id) { log.info("获取用户id为 " + id + "的信息"); return new User(id, "mrbird", "123456"); } @GetMapping public List get() { List list = new ArrayList<>(); list.add(new User(1L, "mrbird", "123456")); list.add(new User(2L, "scott", "123456")); log.info("获取用户信息 " + list); return list; } @PostMapping public void add(@RequestBody User user) { log.info("新增用户成功 " + user); } @PutMapping public void update(@RequestBody User user) { log.info("更新用户成功 " + user); } @DeleteMapping("/{id:\\d+}") public void delete(@PathVariable Long id) { log.info("删除用户成功 " + id); } } ================================================ FILE: 39.Spring-Cloud-Zuul-Router/Eureka-Client/src/main/java/com/example/demo/domain/User.java ================================================ package com.example.demo.domain; import java.io.Serializable; public class User implements Serializable { private static final long serialVersionUID = 1339434510787399891L; private Long id; private String username; private String password; public User() { } public User(Long id, String username, String password) { this.id = id; this.username = username; this.password = password; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", password='" + password + '\'' + '}'; } } ================================================ FILE: 39.Spring-Cloud-Zuul-Router/Eureka-Client/src/main/resources/application.yml ================================================ server: port: 8082 spring: application: name: Server-Provider eureka: client: register-with-eureka: true fetch-registry: true serviceUrl: defaultZone: http://mrbird:123456@peer1:8080/eureka/,http://mrbird:123456@peer2:8081/eureka/ ================================================ FILE: 39.Spring-Cloud-Zuul-Router/Eureka-Service/pom.xml ================================================ 4.0.0 com.example Eureka-Service 0.0.1-SNAPSHOT jar Eureka-Service Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.13.RELEASE UTF-8 UTF-8 1.8 org.springframework.cloud spring-cloud-dependencies Edgware.SR3 pom import org.springframework.cloud spring-cloud-starter-eureka-server org.springframework.boot spring-boot-starter-security nexus-aliyun Nexus aliyun http://maven.aliyun.com/nexus/content/groups/public org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 39.Spring-Cloud-Zuul-Router/Eureka-Service/src/main/java/com/example/demo/DemoApplication.java ================================================ package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @EnableEurekaServer @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ================================================ FILE: 39.Spring-Cloud-Zuul-Router/Eureka-Service/src/main/resources/application-peer1.yml ================================================ server: port: 8080 spring: application: name: Eureka-Server eureka: instance: hostname: peer1 client: serviceUrl: defaultZone: http://mrbird:123456@peer2:8081/eureka/ server: enable-self-preservation: false ================================================ FILE: 39.Spring-Cloud-Zuul-Router/Eureka-Service/src/main/resources/application-peer2.yml ================================================ server: port: 8081 spring: application: name: Eureka-Server eureka: instance: hostname: peer2 client: serviceUrl: defaultZone: http://mrbird:123456@peer1:8080/eureka/ server: enable-self-preservation: false ================================================ FILE: 39.Spring-Cloud-Zuul-Router/Eureka-Service/src/main/resources/application.yml ================================================ security: basic: enabled: true user: name: mrbird password: 123456 spring: profiles: active: peer1 ================================================ FILE: 39.Spring-Cloud-Zuul-Router/Feign-Consumer/pom.xml ================================================ 4.0.0 com.example Feign-Consumer 0.0.1-SNAPSHOT jar Feign-Consumer Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.13.RELEASE UTF-8 UTF-8 1.8 org.springframework.cloud spring-cloud-dependencies Edgware.SR3 pom import org.springframework.cloud spring-cloud-starter-eureka org.springframework.boot spring-boot-starter org.springframework.cloud spring-cloud-starter-feign org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 39.Spring-Cloud-Zuul-Router/Feign-Consumer/src/main/java/com/example/demo/DemoApplication.java ================================================ package com.example.demo; import feign.Logger; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.netflix.feign.EnableFeignClients; import org.springframework.context.annotation.Bean; @EnableDiscoveryClient @EnableFeignClients @SpringBootApplication public class DemoApplication { @Bean Logger.Level feignLoggerLevel() { return Logger.Level.FULL; } public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ================================================ FILE: 39.Spring-Cloud-Zuul-Router/Feign-Consumer/src/main/java/com/example/demo/controller/TestController.java ================================================ package com.example.demo.controller; import com.example.demo.domain.User; import com.example.demo.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import java.util.List; @RestController public class TestController { @Autowired private UserService userService; @GetMapping("user/{id}") public User getUser(@PathVariable Long id) { return userService.get(id); } @GetMapping("user") public List getUsers() { return userService.get(); } @PostMapping("user") public void addUser() { User user = new User(1L, "mrbird", "123456"); userService.add(user); } @PutMapping("user") public void updateUser() { User user = new User(1L, "mrbird", "123456"); userService.update(user); } @DeleteMapping("user/{id}") public void deleteUser(@PathVariable Long id) { userService.delete(id); } } ================================================ FILE: 39.Spring-Cloud-Zuul-Router/Feign-Consumer/src/main/java/com/example/demo/domain/User.java ================================================ package com.example.demo.domain; import java.io.Serializable; public class User implements Serializable { private static final long serialVersionUID = 1339434510787399891L; private Long id; private String username; private String password; public User() { } public User(Long id, String username, String password) { this.id = id; this.username = username; this.password = password; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", password='" + password + '\'' + '}'; } } ================================================ FILE: 39.Spring-Cloud-Zuul-Router/Feign-Consumer/src/main/java/com/example/demo/service/UserService.java ================================================ package com.example.demo.service; import com.example.demo.domain.User; import org.springframework.cloud.netflix.feign.FeignClient; import org.springframework.web.bind.annotation.*; import java.util.List; /** * @author MrBird */ @FeignClient(value = "Server-Provider", fallback = UserServiceFallback.class) public interface UserService { @GetMapping("user/{id}") public User get(@PathVariable("id") Long id); @GetMapping("user") public List get(); @PostMapping("user") public void add(@RequestBody User user); @PutMapping("user") public void update(@RequestBody User user); @DeleteMapping("user/{id}") public void delete(@PathVariable("id") Long id); } ================================================ FILE: 39.Spring-Cloud-Zuul-Router/Feign-Consumer/src/main/java/com/example/demo/service/UserServiceFallback.java ================================================ package com.example.demo.service; import com.example.demo.domain.User; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import java.util.List; /** * @author MrBird */ @Component public class UserServiceFallback implements UserService { private Logger log = LoggerFactory.getLogger(this.getClass()); @Override public User get(Long id) { return new User(-1L, "default", "123456"); } @Override public List get() { return null; } @Override public void add(User user) { log.info("test fallback"); } @Override public void update(User user) { log.info("test fallback"); } @Override public void delete(Long id) { log.info("test fallback"); } } ================================================ FILE: 39.Spring-Cloud-Zuul-Router/Feign-Consumer/src/main/resources/application.yml ================================================ server: port: 9000 spring: application: name: Server-Consumer eureka: client: serviceUrl: defaultZone: http://mrbird:123456@peer1:8080/eureka/,http://mrbird:123456@peer2:8081/eureka/ feign: hystrix: enabled: true logging: level: com: example: demo: service: UserService: debug ================================================ FILE: 39.Spring-Cloud-Zuul-Router/Zuul-Gateway/pom.xml ================================================ 4.0.0 com.example Zuul-Gateway 0.0.1-SNAPSHOT jar demo Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.13.RELEASE UTF-8 UTF-8 1.8 org.springframework.cloud spring-cloud-dependencies Edgware.SR3 pom import org.springframework.boot spring-boot-starter org.springframework.cloud spring-cloud-starter-zuul org.springframework.cloud spring-cloud-starter-eureka org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 39.Spring-Cloud-Zuul-Router/Zuul-Gateway/src/main/java/com/example/demo/DemoApplication.java ================================================ package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.netflix.zuul.EnableZuulProxy; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @EnableZuulProxy @EnableDiscoveryClient @SpringBootApplication @RestController public class DemoApplication { @GetMapping("/test/hello") public String hello() { return "hello zuul"; } public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ================================================ FILE: 39.Spring-Cloud-Zuul-Router/Zuul-Gateway/src/main/java/com/example/demo/filter/PreSendForwardFilter.java ================================================ package com.example.demo.filter; import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.context.RequestContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; @Component public class PreSendForwardFilter extends ZuulFilter { private Logger log = LoggerFactory.getLogger(this.getClass()); @Override public String filterType() { return "pre"; } @Override public int filterOrder() { return 1; } @Override public boolean shouldFilter() { return true; } @Override public Object run() { RequestContext requestContext = RequestContext.getCurrentContext(); HttpServletRequest request = requestContext.getRequest(); String host = request.getRemoteHost(); String method = request.getMethod(); String uri = request.getRequestURI(); log.info("请求URI:{},HTTP Method:{},请求IP:{}", uri, method, host); return null; } } ================================================ FILE: 39.Spring-Cloud-Zuul-Router/Zuul-Gateway/src/main/resources/application.yml ================================================ spring: application: name: Zuul-Gateway server: port: 12580 eureka: client: serviceUrl: defaultZone: http://mrbird:123456@peer1:8080/eureka/,http://mrbird:123456@peer2:8081/eureka/ zuul: routes: api-a: path: /api-a/** url: http://localhost:8082 api-b: path: /api-b/** serviceId: server-provider api-c: path: /api-c/** serviceId: server-consumer api-d: path: /api-c/user/1 serviceId: lol api-e: path: /api-e/** url: forward:/test ignored-services: server-consumer sensitive-headers: add-host-header: true ================================================ FILE: 40.Spring-Boot-Dubbo-Zookeeper/common-api/pom.xml ================================================ dubbo-boot cc.mrbird 1.0 4.0.0 common-api ================================================ FILE: 40.Spring-Boot-Dubbo-Zookeeper/common-api/src/main/java/cc/mrbird/common/api/HelloService.java ================================================ package cc.mrbird.common.api; public interface HelloService { String hello(String message); } ================================================ FILE: 40.Spring-Boot-Dubbo-Zookeeper/pom.xml ================================================ 4.0.0 cc.mrbird dubbo-boot pom 1.0 dubbo-boot Spring Boot-Dubbo-ZooKeeper common-api server-provider server-consumer org.springframework.boot spring-boot-starter-parent 2.0.4.RELEASE UTF-8 UTF-8 1.8 1.0 org.springframework.boot spring-boot-starter-web com.alibaba.boot dubbo-spring-boot-starter 0.2.0 org.apache.zookeeper zookeeper 3.4.8 com.101tec zkclient 0.10 org.apache.maven.plugins maven-compiler-plugin ${java.version} ${java.version} ${project.build.sourceEncoding} ================================================ FILE: 40.Spring-Boot-Dubbo-Zookeeper/server-consumer/pom.xml ================================================ dubbo-boot cc.mrbird 1.0 4.0.0 server-consumer cc.mrbird common-api ${project.version} ================================================ FILE: 40.Spring-Boot-Dubbo-Zookeeper/server-consumer/src/main/java/cc/mrbird/ConsumerApplicaiton.java ================================================ package cc.mrbird; import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @EnableDubbo @SpringBootApplication public class ConsumerApplicaiton { public static void main(String[] args) { SpringApplication.run(ConsumerApplicaiton.class, args); } } ================================================ FILE: 40.Spring-Boot-Dubbo-Zookeeper/server-consumer/src/main/java/cc/mrbird/consumer/controller/HelloController.java ================================================ package cc.mrbird.consumer.controller; import cc.mrbird.common.api.HelloService; import com.alibaba.dubbo.config.annotation.Reference; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; @RestController public class HelloController { @Reference private HelloService helloService; @GetMapping("/hello/{message}") public String hello(@PathVariable String message) { return this.helloService.hello(message); } } ================================================ FILE: 40.Spring-Boot-Dubbo-Zookeeper/server-consumer/src/main/resources/application.yml ================================================ server: port: 8081 dubbo: application: # 服务名称,保持唯一 name: server-consumer # zookeeper地址,用于从中获取注册的服务 registry: address: zookeeper://127.0.0.1:2181 protocol: # dubbo协议,固定写法 name: dubbo ================================================ FILE: 40.Spring-Boot-Dubbo-Zookeeper/server-provider/pom.xml ================================================ dubbo-boot cc.mrbird 1.0 4.0.0 server-provider cc.mrbird common-api ${project.version} ================================================ FILE: 40.Spring-Boot-Dubbo-Zookeeper/server-provider/src/main/java/cc/mrbird/ProviderApplicaiton.java ================================================ package cc.mrbird; import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @EnableDubbo @SpringBootApplication public class ProviderApplicaiton { public static void main(String[] args) { SpringApplication.run(ProviderApplicaiton.class, args); System.out.println("complete"); } } ================================================ FILE: 40.Spring-Boot-Dubbo-Zookeeper/server-provider/src/main/java/cc/mrbird/provider/service/HelloServiceImpl.java ================================================ package cc.mrbird.provider.service; import cc.mrbird.common.api.HelloService; import com.alibaba.dubbo.config.annotation.Service; import org.springframework.stereotype.Component; @Service(interfaceClass = HelloService.class) @Component public class HelloServiceImpl implements HelloService { @Override public String hello(String message) { return "hello," + message; } } ================================================ FILE: 40.Spring-Boot-Dubbo-Zookeeper/server-provider/src/main/resources/application.yml ================================================ server: port: 8080 dubbo: application: # 服务名称,保持唯一 name: server-provider # zookeeper地址,用于向其注册服务 registry: address: zookeeper://127.0.0.1:2181 #暴露服务方式 protocol: # dubbo协议,固定写法 name: dubbo # 暴露服务端口 (默认是20880,不同的服务提供者端口不能重复) port: 20880 ================================================ FILE: 41.Spring-Cloud-Config/Eureka-Service/pom.xml ================================================ 4.0.0 com.example Eureka-Service 0.0.1-SNAPSHOT jar Eureka-Service Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.13.RELEASE UTF-8 UTF-8 1.8 org.springframework.cloud spring-cloud-dependencies Edgware.SR3 pom import org.springframework.cloud spring-cloud-starter-eureka-server org.springframework.boot spring-boot-starter-security nexus-aliyun Nexus aliyun http://maven.aliyun.com/nexus/content/groups/public org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 41.Spring-Cloud-Config/Eureka-Service/src/main/java/com/example/demo/DemoApplication.java ================================================ package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @EnableEurekaServer @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ================================================ FILE: 41.Spring-Cloud-Config/Eureka-Service/src/main/resources/application-peer1.yml ================================================ server: port: 8080 spring: application: name: Eureka-Server eureka: instance: hostname: peer1 client: serviceUrl: defaultZone: http://mrbird:123456@peer2:8081/eureka/ server: enable-self-preservation: false ================================================ FILE: 41.Spring-Cloud-Config/Eureka-Service/src/main/resources/application-peer2.yml ================================================ server: port: 8081 spring: application: name: Eureka-Server eureka: instance: hostname: peer2 client: serviceUrl: defaultZone: http://mrbird:123456@peer1:8080/eureka/ server: enable-self-preservation: false ================================================ FILE: 41.Spring-Cloud-Config/Eureka-Service/src/main/resources/application.yml ================================================ security: basic: enabled: true user: name: mrbird password: 123456 spring: profiles: active: peer1 ================================================ FILE: 41.Spring-Cloud-Config/config-client/pom.xml ================================================ 4.0.0 cc.mrbird Config-Client 0.0.1-SNAPSHOT jar demo Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.13.RELEASE UTF-8 UTF-8 1.8 org.springframework.cloud spring-cloud-dependencies Edgware.SR3 pom import org.springframework.boot spring-boot-starter org.springframework.boot spring-boot-starter-web org.springframework.cloud spring-cloud-starter-config org.springframework.boot spring-boot-starter-actuator org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 41.Spring-Cloud-Config/config-client/src/main/java/cc/mrbird/demo/DemoApplication.java ================================================ package cc.mrbird.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; @SpringBootApplication // @EnableDiscoveryClient public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ================================================ FILE: 41.Spring-Cloud-Config/config-client/src/main/java/cc/mrbird/demo/controller/TestController.java ================================================ package cc.mrbird.demo.controller; import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RefreshScope public class TestController { @Value("${message}") private String message; @GetMapping("message") public String getMessage() { return this.message; } } ================================================ FILE: 41.Spring-Cloud-Config/config-client/src/main/resources/bootstrap.yml ================================================ spring: application: name: febs cloud: config: profile: dev label: master uri: http://localhost:12580 username: mrbird password: 123456 # discovery: # enabled: true # service-id: config-server #eureka: # client: # serviceUrl: # defaultZone: http://mrbird:123456@peer1:8080/eureka/,http://mrbird:123456@peer2:8081/eureka/ server: port: 12581 management: security: enabled: false ================================================ FILE: 41.Spring-Cloud-Config/config-server/pom.xml ================================================ 4.0.0 cc.mrbird Config-Server 0.0.1-SNAPSHOT jar demo Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.13.RELEASE UTF-8 UTF-8 1.8 org.springframework.cloud spring-cloud-dependencies Edgware.SR3 pom import org.springframework.boot spring-boot-starter org.springframework.cloud spring-cloud-config-server org.springframework.boot spring-boot-starter-security org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 41.Spring-Cloud-Config/config-server/src/main/java/cc/mrbird/demo/DemoApplication.java ================================================ package cc.mrbird.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.config.server.EnableConfigServer; @SpringBootApplication @EnableConfigServer // @EnableDiscoveryClient public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ================================================ FILE: 41.Spring-Cloud-Config/config-server/src/main/resources/application.yml ================================================ spring: application: name: config-server cloud: config: server: git: uri: xxx username: xxx password: xxx # search-paths: '{application}' clone-on-start: true server: port: 12580 security: user: name: mrbird password: 123456 #eureka: # client: # serviceUrl: # defaultZone: http://mrbird:123456@peer1:8080/eureka/,http://mrbird:123456@peer2:8081/eureka/ ================================================ FILE: 41.Spring-Cloud-Config/config-server/src/main/resources/bootstrap.yml ================================================ #encrypt: ## key: hello #encrypt: # key-store: # location: classpath:config-server.keystore # alias: Config-Server # password: 123456 # secret: 654321 ================================================ FILE: 41.Spring-Cloud-Config/properties/febs-dev.yml ================================================ message: 'dev properties (master v1.0)' ================================================ FILE: 41.Spring-Cloud-Config/properties/febs-pro.yml ================================================ message: 'pro properties (master v1.0)' ================================================ FILE: 41.Spring-Cloud-Config/properties/febs-test.yml ================================================ message: 'test properties (master v1.0)' ================================================ FILE: 41.Spring-Cloud-Config/properties/febs.yml ================================================ message: 'default properties (master v1.0)' ================================================ FILE: 42.Spring-Cloud-Bus/Eureka-Service/pom.xml ================================================ 4.0.0 com.example Eureka-Service 0.0.1-SNAPSHOT jar Eureka-Service Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.13.RELEASE UTF-8 UTF-8 1.8 org.springframework.cloud spring-cloud-dependencies Edgware.SR3 pom import org.springframework.cloud spring-cloud-starter-eureka-server org.springframework.boot spring-boot-starter-security nexus-aliyun Nexus aliyun http://maven.aliyun.com/nexus/content/groups/public org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 42.Spring-Cloud-Bus/Eureka-Service/src/main/java/com/example/demo/DemoApplication.java ================================================ package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @EnableEurekaServer @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ================================================ FILE: 42.Spring-Cloud-Bus/Eureka-Service/src/main/resources/application-peer1.yml ================================================ server: port: 8080 spring: application: name: Eureka-Server eureka: instance: hostname: peer1 client: serviceUrl: defaultZone: http://mrbird:123456@peer2:8081/eureka/ server: enable-self-preservation: false ================================================ FILE: 42.Spring-Cloud-Bus/Eureka-Service/src/main/resources/application-peer2.yml ================================================ server: port: 8081 spring: application: name: Eureka-Server eureka: instance: hostname: peer2 client: serviceUrl: defaultZone: http://mrbird:123456@peer1:8080/eureka/ server: enable-self-preservation: false ================================================ FILE: 42.Spring-Cloud-Bus/Eureka-Service/src/main/resources/application.yml ================================================ security: basic: enabled: true user: name: mrbird password: 123456 spring: profiles: active: peer1 ================================================ FILE: 42.Spring-Cloud-Bus/config-client/pom.xml ================================================ 4.0.0 cc.mrbird Config-Client 0.0.1-SNAPSHOT jar demo Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.13.RELEASE UTF-8 UTF-8 1.8 org.springframework.cloud spring-cloud-dependencies Edgware.SR3 pom import org.springframework.boot spring-boot-starter org.springframework.boot spring-boot-starter-web org.springframework.cloud spring-cloud-starter-config org.springframework.boot spring-boot-starter-actuator org.springframework.cloud spring-cloud-starter-eureka org.springframework.cloud spring-cloud-starter-bus-amqp org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 42.Spring-Cloud-Bus/config-client/src/main/java/cc/mrbird/demo/DemoApplication.java ================================================ package cc.mrbird.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; @SpringBootApplication @EnableDiscoveryClient public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ================================================ FILE: 42.Spring-Cloud-Bus/config-client/src/main/java/cc/mrbird/demo/controller/TestController.java ================================================ package cc.mrbird.demo.controller; import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RefreshScope public class TestController { @Value("${message}") private String message; @GetMapping("message") public String getMessage() { return this.message; } } ================================================ FILE: 42.Spring-Cloud-Bus/config-client/src/main/resources/bootstrap.yml ================================================ spring: application: name: febs cloud: config: profile: dev label: master uri: http://localhost:12580 username: mrbird password: 123456 discovery: enabled: true service-id: config-server rabbitmq: host: localhost port: 5672 username: guest password: guest eureka: client: serviceUrl: defaultZone: http://mrbird:123456@peer1:8080/eureka/,http://mrbird:123456@peer2:8081/eureka/ server: port: 12581 management: security: enabled: false ================================================ FILE: 42.Spring-Cloud-Bus/config-server/pom.xml ================================================ 4.0.0 cc.mrbird Config-Server 0.0.1-SNAPSHOT jar demo Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.13.RELEASE UTF-8 UTF-8 1.8 org.springframework.cloud spring-cloud-dependencies Edgware.SR3 pom import org.springframework.boot spring-boot-starter org.springframework.cloud spring-cloud-config-server org.springframework.boot spring-boot-starter-security org.springframework.cloud spring-cloud-starter-eureka org.springframework.boot spring-boot-starter-actuator org.springframework.cloud spring-cloud-starter-bus-amqp org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 42.Spring-Cloud-Bus/config-server/src/main/java/cc/mrbird/demo/DemoApplication.java ================================================ package cc.mrbird.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.config.server.EnableConfigServer; @SpringBootApplication @EnableConfigServer @EnableDiscoveryClient public class DemoApplication { private String a; public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ================================================ FILE: 42.Spring-Cloud-Bus/config-server/src/main/resources/application.yml ================================================ spring: application: name: config-server cloud: config: server: git: uri: xxx username: xxx password: xxx search-paths: '{application}' clone-on-start: true rabbitmq: host: localhost port: 5672 username: guest password: guest server: port: 12580 security: user: name: mrbird password: 123456 eureka: client: serviceUrl: defaultZone: http://mrbird:123456@peer1:8080/eureka/,http://mrbird:123456@peer2:8081/eureka/ ================================================ FILE: 42.Spring-Cloud-Bus/config-server/src/main/resources/bootstrap.yml ================================================ #encrypt: ## key: hello #encrypt: # key-store: # location: classpath:config-server.keystore # alias: Config-Server # password: 123456 # secret: 654321 ================================================ FILE: 43.Spring-Cloud-Sleuth/Eureka-Service/pom.xml ================================================ 4.0.0 com.example Eureka-Service 0.0.1-SNAPSHOT jar Eureka-Service Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.13.RELEASE UTF-8 UTF-8 1.8 org.springframework.cloud spring-cloud-dependencies Edgware.SR3 pom import org.springframework.cloud spring-cloud-starter-eureka-server org.springframework.boot spring-boot-starter-security nexus-aliyun Nexus aliyun http://maven.aliyun.com/nexus/content/groups/public org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 43.Spring-Cloud-Sleuth/Eureka-Service/src/main/java/com/example/demo/DemoApplication.java ================================================ package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @EnableEurekaServer @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ================================================ FILE: 43.Spring-Cloud-Sleuth/Eureka-Service/src/main/resources/application-peer1.yml ================================================ server: port: 8080 spring: application: name: Eureka-Server eureka: instance: hostname: peer1 client: serviceUrl: defaultZone: http://mrbird:123456@peer2:8081/eureka/ server: enable-self-preservation: false ================================================ FILE: 43.Spring-Cloud-Sleuth/Eureka-Service/src/main/resources/application-peer2.yml ================================================ server: port: 8081 spring: application: name: Eureka-Server eureka: instance: hostname: peer2 client: serviceUrl: defaultZone: http://mrbird:123456@peer1:8080/eureka/ server: enable-self-preservation: false ================================================ FILE: 43.Spring-Cloud-Sleuth/Eureka-Service/src/main/resources/application.yml ================================================ security: basic: enabled: true user: name: mrbird password: 123456 spring: profiles: active: peer1 ================================================ FILE: 43.Spring-Cloud-Sleuth/Server-Provider1/pom.xml ================================================ 4.0.0 cc.mrbird Server-Provider1 0.0.1-SNAPSHOT jar demo Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.13.RELEASE UTF-8 UTF-8 1.8 org.springframework.cloud spring-cloud-dependencies Edgware.SR3 pom import org.springframework.boot spring-boot-starter org.springframework.cloud spring-cloud-starter-eureka org.springframework.cloud spring-cloud-starter-ribbon org.springframework.cloud spring-cloud-starter-sleuth org.springframework.cloud spring-cloud-sleuth-zipkin org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 43.Spring-Cloud-Sleuth/Server-Provider1/src/main/java/com/example/demo/DemoApplication.java ================================================ package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; @SpringBootApplication @EnableDiscoveryClient public class DemoApplication { @Bean @LoadBalanced RestTemplate restTemplate() { return new RestTemplate(); } public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ================================================ FILE: 43.Spring-Cloud-Sleuth/Server-Provider1/src/main/java/com/example/demo/controller/HelloController.java ================================================ package com.example.demo.controller; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; @RestController @RequestMapping("hello") public class HelloController { private Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired private RestTemplate restTemplate; @GetMapping public String hello() { logger.info("调用server-provider1的hello接口"); return this.restTemplate.getForEntity("http://server-provider2/hello", String.class).getBody(); } } ================================================ FILE: 43.Spring-Cloud-Sleuth/Server-Provider1/src/main/resources/application.yml ================================================ spring: application: name: server-provider1 zipkin: base-url: http://localhost:9100 sleuth: sampler: percentage: 1 server: port: 9000 eureka: client: serviceUrl: defaultZone: http://mrbird:123456@peer1:8080/eureka/,http://mrbird:123456@peer2:8081/eureka/ ================================================ FILE: 43.Spring-Cloud-Sleuth/Server-Provider2/pom.xml ================================================ 4.0.0 cc.mrbird Server-Provider2 0.0.1-SNAPSHOT jar demo Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.13.RELEASE UTF-8 UTF-8 1.8 org.springframework.cloud spring-cloud-dependencies Edgware.SR3 pom import org.springframework.boot spring-boot-starter org.springframework.cloud spring-cloud-starter-eureka org.springframework.cloud spring-cloud-starter-ribbon org.springframework.cloud spring-cloud-starter-sleuth org.springframework.cloud spring-cloud-sleuth-zipkin org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 43.Spring-Cloud-Sleuth/Server-Provider2/src/main/java/com/example/demo/DemoApplication.java ================================================ package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; @SpringBootApplication @EnableDiscoveryClient public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ================================================ FILE: 43.Spring-Cloud-Sleuth/Server-Provider2/src/main/java/com/example/demo/controller/HelloController.java ================================================ package com.example.demo.controller; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("hello") public class HelloController { private Logger logger = LoggerFactory.getLogger(this.getClass()); @GetMapping public String hello() { logger.info("调用server-provider2的hello接口"); return "hello world"; } } ================================================ FILE: 43.Spring-Cloud-Sleuth/Server-Provider2/src/main/resources/application.yml ================================================ spring: application: name: server-provider2 zipkin: base-url: http://localhost:9100 sleuth: sampler: percentage: 1 server: port: 9001 eureka: client: serviceUrl: defaultZone: http://mrbird:123456@peer1:8080/eureka/,http://mrbird:123456@peer2:8081/eureka/ ================================================ FILE: 43.Spring-Cloud-Sleuth/Zipkin-Server/pom.xml ================================================ 4.0.0 cc.mrbird Zipkin-Server 0.0.1-SNAPSHOT jar demo Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.13.RELEASE UTF-8 UTF-8 1.8 org.springframework.cloud spring-cloud-dependencies Edgware.SR3 pom import org.springframework.boot spring-boot-starter io.zipkin.java zipkin-server io.zipkin.java zipkin-autoconfigure-ui io.zipkin.java zipkin-autoconfigure-storage-mysql org.springframework.boot spring-boot-starter-jdbc mysql mysql-connector-java org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 43.Spring-Cloud-Sleuth/Zipkin-Server/src/main/java/com/example/demo/DemoApplication.java ================================================ package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.sleuth.zipkin.stream.EnableZipkinStreamServer; @SpringBootApplication // @EnableZipkinServer @EnableZipkinStreamServer public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ================================================ FILE: 43.Spring-Cloud-Sleuth/Zipkin-Server/src/main/resources/application.yml ================================================ spring: application: name: zipkin-server datasource: url: jdbc:mysql://127.0.0.1:3306/zipkin?useUnicode=true&characterEncoding=utf-8 driver-class-name: com.mysql.jdbc.Driver username: root password: 123456 server: port: 9100 zipkin: storage: type: mysql ================================================ FILE: 44.Spring-Boot-Autoconfiguration/pom.xml ================================================ 4.0.0 org.springframework.boot spring-boot-starter-parent 2.1.0.RELEASE com.example autoconfig 0.0.1-SNAPSHOT demo Demo project for Spring Boot 1.8 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test test org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 44.Spring-Boot-Autoconfiguration/src/main/java/com/example/demo/DemoApplication.java ================================================ package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ================================================ FILE: 44.Spring-Boot-Autoconfiguration/src/main/java/com/example/demo/annotation/EnableHelloWorld.java ================================================ package com.example.demo.annotation; import com.example.demo.configuration.HelloWorldConfiguration; import org.springframework.context.annotation.Import; import java.lang.annotation.*; /** * @author MrBird */ @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented // @Import(HelloWorldImportSelector.class) @Import(HelloWorldConfiguration.class) public @interface EnableHelloWorld { } ================================================ FILE: 44.Spring-Boot-Autoconfiguration/src/main/java/com/example/demo/annotation/FirstLevelService.java ================================================ package com.example.demo.annotation; import org.springframework.stereotype.Repository; import org.springframework.stereotype.Service; import java.lang.annotation.*; @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Service public @interface FirstLevelService { String value() default ""; } ================================================ FILE: 44.Spring-Boot-Autoconfiguration/src/main/java/com/example/demo/annotation/SecondLevelService.java ================================================ package com.example.demo.annotation; import java.lang.annotation.*; @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @FirstLevelService public @interface SecondLevelService { String value() default ""; } ================================================ FILE: 44.Spring-Boot-Autoconfiguration/src/main/java/com/example/demo/bootstrap/EnableAutoConfigurationBootstrap.java ================================================ package com.example.demo.bootstrap; import org.springframework.boot.WebApplicationType; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.context.ConfigurableApplicationContext; /** * @author MrBird */ @EnableAutoConfiguration public class EnableAutoConfigurationBootstrap { public static void main(String[] args) { ConfigurableApplicationContext context = new SpringApplicationBuilder(EnableAutoConfigurationBootstrap.class) .web(WebApplicationType.NONE) .run(args); String hello = context.getBean("hello", String.class); System.out.println("hello Bean: " + hello); context.close(); } } ================================================ FILE: 44.Spring-Boot-Autoconfiguration/src/main/java/com/example/demo/bootstrap/ServiceBootstrap.java ================================================ package com.example.demo.bootstrap; import com.example.demo.service.TestService; import org.springframework.boot.WebApplicationType; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.ComponentScan; /** * @author MrBird */ @ComponentScan("com.example.demo.service") public class ServiceBootstrap { public static void main(String[] args) { ConfigurableApplicationContext context = new SpringApplicationBuilder(ServiceBootstrap.class) .web(WebApplicationType.NONE) .run(args); TestService testService = context.getBean("testService", TestService.class); System.out.println("TestService Bean: " + testService); context.close(); } } ================================================ FILE: 44.Spring-Boot-Autoconfiguration/src/main/java/com/example/demo/bootstrap/TestEnableBootstap.java ================================================ package com.example.demo.bootstrap; import com.example.demo.annotation.EnableHelloWorld; import org.springframework.boot.WebApplicationType; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.context.ConfigurableApplicationContext; /** * @author MrBird */ @EnableHelloWorld public class TestEnableBootstap { public static void main(String[] args) { ConfigurableApplicationContext context = new SpringApplicationBuilder(TestEnableBootstap.class) .web(WebApplicationType.NONE) .run(args); String hello = context.getBean("hello", String.class); System.out.println("hello Bean: " + hello); context.close(); } } ================================================ FILE: 44.Spring-Boot-Autoconfiguration/src/main/java/com/example/demo/configuration/HelloWorldAutoConfiguration.java ================================================ package com.example.demo.configuration; import com.example.demo.annotation.EnableHelloWorld; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Configuration; /** * @author MrBird */ @Configuration @EnableHelloWorld @ConditionalOnProperty(name = "helloworld", havingValue = "true") public class HelloWorldAutoConfiguration { } ================================================ FILE: 44.Spring-Boot-Autoconfiguration/src/main/java/com/example/demo/configuration/HelloWorldConfiguration.java ================================================ package com.example.demo.configuration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * @author MrBird */ @Configuration public class HelloWorldConfiguration { @Bean public String hello() { return "hello world"; } } ================================================ FILE: 44.Spring-Boot-Autoconfiguration/src/main/java/com/example/demo/selector/HelloWorldImportSelector.java ================================================ package com.example.demo.selector; import com.example.demo.configuration.HelloWorldConfiguration; import org.springframework.context.annotation.ImportSelector; import org.springframework.core.type.AnnotationMetadata; /** * @author MrBird */ public class HelloWorldImportSelector implements ImportSelector { @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) { return new String[]{HelloWorldConfiguration.class.getName()}; } } ================================================ FILE: 44.Spring-Boot-Autoconfiguration/src/main/java/com/example/demo/service/TestService.java ================================================ package com.example.demo.service; import com.example.demo.annotation.FirstLevelService; import com.example.demo.annotation.SecondLevelService; /** * @author MrBird */ @SecondLevelService public class TestService { } ================================================ FILE: 44.Spring-Boot-Autoconfiguration/src/main/resources/META-INF/spring.factories ================================================ # Auto Configure org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.example.demo.configuration.HelloWorldAutoConfiguration ================================================ FILE: 44.Spring-Boot-Autoconfiguration/src/main/resources/application.properties ================================================ helloworld=true ================================================ FILE: 44.Spring-Boot-Autoconfiguration/src/test/java/com/example/demo/DemoApplicationTests.java ================================================ package com.example.demo; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) @SpringBootTest public class DemoApplicationTests { @Test public void contextLoads() { } } ================================================ FILE: 45.Spring-Boot-SpringApplication/pom.xml ================================================ 4.0.0 org.springframework.boot spring-boot-starter-parent 2.1.0.RELEASE com.example SpringApplication 0.0.1-SNAPSHOT demo Demo project for Spring Boot 1.8 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test test org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 45.Spring-Boot-SpringApplication/src/main/java/com/example/demo/DemoApplication.java ================================================ package com.example.demo; import org.springframework.boot.Banner; import org.springframework.boot.SpringApplication; import org.springframework.boot.WebApplicationType; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.builder.SpringApplicationBuilder; @SpringBootApplication public class DemoApplication { public static void main(String[] args) { // SpringApplication application = new SpringApplication(DemoApplication.class); // application.setBannerMode(Banner.Mode.OFF); // application.setWebApplicationType(WebApplicationType.NONE); // application.setHeadless(true); // application.run(args); new SpringApplicationBuilder(DemoApplication.class) .web(WebApplicationType.NONE) .run(args); } } ================================================ FILE: 45.Spring-Boot-SpringApplication/src/main/java/com/example/demo/initializer/AfterHelloApplicationContextInitializer.java ================================================ package com.example.demo.initializer; import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.core.Ordered; /** * @author MrBird */ public class AfterHelloApplicationContextInitializer implements ApplicationContextInitializer, Ordered { @Override public void initialize(ConfigurableApplicationContext applicationContext) { System.out.println("AfterHelloApplicationContextInitializer: " + applicationContext.getId()); } @Override public int getOrder() { return Ordered.LOWEST_PRECEDENCE; } } ================================================ FILE: 45.Spring-Boot-SpringApplication/src/main/java/com/example/demo/initializer/HelloApplicationContextInitializer.java ================================================ package com.example.demo.initializer; import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; /** * @author MrBird */ @Order(Ordered.HIGHEST_PRECEDENCE) public class HelloApplicationContextInitializer implements ApplicationContextInitializer { @Override public void initialize(ConfigurableApplicationContext applicationContext) { System.out.println("ConfigurableApplicationContext.id - " + applicationContext.getId()); } } ================================================ FILE: 45.Spring-Boot-SpringApplication/src/main/java/com/example/demo/listener/AfterContextClosedEventListener.java ================================================ package com.example.demo.listener; import org.springframework.context.ApplicationListener; import org.springframework.context.event.ContextClosedEvent; import org.springframework.core.Ordered; /** * @author MrBird */ public class AfterContextClosedEventListener implements ApplicationListener, Ordered { @Override public void onApplicationEvent(ContextClosedEvent event) { System.out.println("AfterContextClosedEvent: " + event.getApplicationContext().getId()); } @Override public int getOrder() { return Ordered.HIGHEST_PRECEDENCE + 1; } } ================================================ FILE: 45.Spring-Boot-SpringApplication/src/main/java/com/example/demo/listener/ContextClosedEventListener.java ================================================ package com.example.demo.listener; import org.springframework.context.ApplicationListener; import org.springframework.context.event.ContextClosedEvent; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; /** * @author MrBird */ @Order(Ordered.HIGHEST_PRECEDENCE) public class ContextClosedEventListener implements ApplicationListener { @Override public void onApplicationEvent(ContextClosedEvent event) { System.out.println("ContextClosedEvent: " + event.getApplicationContext().getId()); } } ================================================ FILE: 45.Spring-Boot-SpringApplication/src/main/java/com/example/demo/listener/HelloApplicationRunListener.java ================================================ package com.example.demo.listener; import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplicationRunListener; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.core.env.ConfigurableEnvironment; /** * @author MrBird */ public class HelloApplicationRunListener implements SpringApplicationRunListener { public HelloApplicationRunListener(SpringApplication application, String[] args) { } @Override public void starting() { System.out.println("HelloApplicationRunListener starting......"); } @Override public void environmentPrepared(ConfigurableEnvironment environment) { } @Override public void contextPrepared(ConfigurableApplicationContext context) { } @Override public void contextLoaded(ConfigurableApplicationContext context) { } @Override public void started(ConfigurableApplicationContext context) { } @Override public void running(ConfigurableApplicationContext context) { } @Override public void failed(ConfigurableApplicationContext context, Throwable exception) { } } ================================================ FILE: 45.Spring-Boot-SpringApplication/src/main/java/com/example/demo/runner/HelloApplicationRunner.java ================================================ package com.example.demo.runner; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.stereotype.Component; /** * @author MrBird */ @Component public class HelloApplicationRunner implements ApplicationRunner { @Override public void run(ApplicationArguments args) { System.out.println("HelloApplicationRunner: hello spring boot"); } } ================================================ FILE: 45.Spring-Boot-SpringApplication/src/main/java/com/example/demo/runner/HelloCommandLineRunner.java ================================================ package com.example.demo.runner; import org.springframework.boot.CommandLineRunner; import org.springframework.stereotype.Component; /** * @author MrBird */ @Component public class HelloCommandLineRunner implements CommandLineRunner { @Override public void run(String... args) { System.out.println("HelloCommandLineRunner: hello spring boot"); } } ================================================ FILE: 45.Spring-Boot-SpringApplication/src/main/resources/META-INF/spring.factories ================================================ # Initializers org.springframework.context.ApplicationContextInitializer=\ com.example.demo.initializer.HelloApplicationContextInitializer,\ com.example.demo.initializer.AfterHelloApplicationContextInitializer # Application Listeners org.springframework.context.ApplicationListener=\ com.example.demo.listener.ContextClosedEventListener,\ com.example.demo.listener.AfterContextClosedEventListener # Run Listeners org.springframework.boot.SpringApplicationRunListener=\ com.example.demo.listener.HelloApplicationRunListener ================================================ FILE: 45.Spring-Boot-SpringApplication/src/main/resources/application.properties ================================================ ================================================ FILE: 45.Spring-Boot-SpringApplication/src/test/java/com/example/demo/DemoApplicationTests.java ================================================ package com.example.demo; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) @SpringBootTest public class DemoApplicationTests { @Test public void contextLoads() { } } ================================================ FILE: 46.Spring-Boot-Hibernate-Validator/pom.xml ================================================ 4.0.0 org.springframework.boot spring-boot-starter-parent 2.1.0.RELEASE com.example validator 0.0.1-SNAPSHOT demo Demo project for Spring Boot 1.8 org.springframework.boot spring-boot-starter-web org.apache.commons commons-lang3 org.springframework.boot spring-boot-starter-test test org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 46.Spring-Boot-Hibernate-Validator/src/main/java/com/example/demo/DemoApplication.java ================================================ package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ================================================ FILE: 46.Spring-Boot-Hibernate-Validator/src/main/java/com/example/demo/controller/TestController.java ================================================ package com.example.demo.controller; import com.example.demo.domain.User; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import javax.validation.Valid; import javax.validation.constraints.Email; import javax.validation.constraints.NotBlank; /** * @author MrBird */ @RestController @Validated public class TestController { @GetMapping("test1") public String test1( @NotBlank(message = "{required}") String name, @Email(message = "{invalid}") String email) { return "success"; } @GetMapping("test2") public String test2(@Valid User user) { return "success"; } } ================================================ FILE: 46.Spring-Boot-Hibernate-Validator/src/main/java/com/example/demo/domain/User.java ================================================ package com.example.demo.domain; import javax.validation.constraints.Email; import javax.validation.constraints.NotBlank; import java.io.Serializable; /** * @author MrBird */ public class User implements Serializable { private static final long serialVersionUID = -2731598327208972274L; @NotBlank(message = "{required}") private String name; @Email(message = "{invalid}") private String email; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } } ================================================ FILE: 46.Spring-Boot-Hibernate-Validator/src/main/java/com/example/demo/handler/GlobalExceptionHandler.java ================================================ package com.example.demo.handler; import org.apache.commons.lang3.StringUtils; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.http.HttpStatus; import org.springframework.validation.BindException; import org.springframework.validation.FieldError; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestControllerAdvice; import javax.validation.ConstraintViolation; import javax.validation.ConstraintViolationException; import javax.validation.Path; import java.util.List; import java.util.Set; /** * @author MrBird */ @RestControllerAdvice @Order(value = Ordered.HIGHEST_PRECEDENCE) public class GlobalExceptionHandler { /** * 统一处理请求参数校验(普通传参) * * @param e ConstraintViolationException * @return FebsResponse */ @ExceptionHandler(value = ConstraintViolationException.class) @ResponseStatus(HttpStatus.BAD_REQUEST) public String handleConstraintViolationException(ConstraintViolationException e) { StringBuilder message = new StringBuilder(); Set> violations = e.getConstraintViolations(); for (ConstraintViolation violation : violations) { Path path = violation.getPropertyPath(); String[] pathArr = StringUtils.splitByWholeSeparatorPreserveAllTokens(path.toString(), "."); message.append(pathArr[1]).append(violation.getMessage()).append(","); } message = new StringBuilder(message.substring(0, message.length() - 1)); return message.toString(); } /** * 统一处理请求参数校验(实体对象传参) * * @param e BindException * @return FebsResponse */ @ExceptionHandler(BindException.class) @ResponseStatus(HttpStatus.BAD_REQUEST) public String validExceptionHandler(BindException e) { StringBuilder message = new StringBuilder(); List fieldErrors = e.getBindingResult().getFieldErrors(); for (FieldError error : fieldErrors) { message.append(error.getField()).append(error.getDefaultMessage()).append(","); } message = new StringBuilder(message.substring(0, message.length() - 1)); return message.toString(); } } ================================================ FILE: 46.Spring-Boot-Hibernate-Validator/src/main/resources/ValidationMessages.properties ================================================ required=\u4e0d\u80fd\u4e3a\u7a7a invalid=\u683c\u5f0f\u4e0d\u5408\u6cd5 ================================================ FILE: 46.Spring-Boot-Hibernate-Validator/src/main/resources/application.properties ================================================ ================================================ FILE: 46.Spring-Boot-Hibernate-Validator/src/test/java/com/example/demo/DemoApplicationTests.java ================================================ package com.example.demo; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) @SpringBootTest public class DemoApplicationTests { @Test public void contextLoads() { } } ================================================ FILE: 47.Spring-Boot-Content-Negotiation/pom.xml ================================================ 4.0.0 org.springframework.boot spring-boot-starter-parent 2.1.0.RELEASE com.example demo 0.0.1-SNAPSHOT demo Demo project for Spring Boot 1.8 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test test org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 47.Spring-Boot-Content-Negotiation/src/main/java/com/example/demo/DemoApplication.java ================================================ package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ================================================ FILE: 47.Spring-Boot-Content-Negotiation/src/main/java/com/example/demo/config/WebConfigurer.java ================================================ package com.example.demo.config; import com.example.demo.converter.PropertiesHttpMessageConverter; import com.example.demo.handler.PropertiesHandlerMethodReturnValueHandler; import com.example.demo.resolver.PropertiesHandlerMethodArgumentResolver; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.method.support.HandlerMethodReturnValueHandler; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter; import javax.annotation.PostConstruct; import java.util.ArrayList; import java.util.List; /** * @author MrBird */ @Configuration public class WebConfigurer implements WebMvcConfigurer { @Autowired private RequestMappingHandlerAdapter requestMappingHandlerAdapter; @PostConstruct public void init() { // 获取当前 RequestMappingHandlerAdapter 所有的 ArgumentResolver对象 List argumentResolvers = requestMappingHandlerAdapter.getArgumentResolvers(); List newArgumentResolvers = new ArrayList<>(argumentResolvers.size() + 1); // 添加 PropertiesHandlerMethodArgumentResolver 到集合第一个位置 newArgumentResolvers.add(0, new PropertiesHandlerMethodArgumentResolver()); // 将原 ArgumentResolver 添加到集合中 newArgumentResolvers.addAll(argumentResolvers); // 重新设置 ArgumentResolver对象集合 requestMappingHandlerAdapter.setArgumentResolvers(newArgumentResolvers); // 获取当前 RequestMappingHandlerAdapter 所有的 returnValueHandlers对象 List returnValueHandlers = requestMappingHandlerAdapter.getReturnValueHandlers(); List newReturnValueHandlers = new ArrayList<>(returnValueHandlers.size() + 1); // 添加 PropertiesHandlerMethodReturnValueHandler 到集合第一个位置 newReturnValueHandlers.add(0, new PropertiesHandlerMethodReturnValueHandler()); // 将原 returnValueHandlers 添加到集合中 newReturnValueHandlers.addAll(returnValueHandlers); // 重新设置 ReturnValueHandlers对象集合 requestMappingHandlerAdapter.setReturnValueHandlers(newReturnValueHandlers); } public void extendMessageConverters(List> converters) { // converters.add(new PropertiesHttpMessageConverter()); // 指定顺序,这里为第一个 converters.add(0, new PropertiesHttpMessageConverter()); } } ================================================ FILE: 47.Spring-Boot-Content-Negotiation/src/main/java/com/example/demo/controller/TestController.java ================================================ package com.example.demo.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import java.util.Properties; /** * @author MrBird */ // @RestController @Controller public class TestController { @GetMapping(value = "test", consumes = "text/properties") @ResponseBody public Properties getUser(@RequestBody Properties properties) { return properties; } @GetMapping(value = "test1", consumes = "text/properties") // @ResponseBody public Properties getUser1(Properties properties) { return properties; } } ================================================ FILE: 47.Spring-Boot-Content-Negotiation/src/main/java/com/example/demo/converter/PropertiesHttpMessageConverter.java ================================================ package com.example.demo.converter; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpInputMessage; import org.springframework.http.HttpOutputMessage; import org.springframework.http.MediaType; import org.springframework.http.converter.AbstractGenericHttpMessageConverter; import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.http.converter.HttpMessageNotWritableException; import java.io.*; import java.lang.reflect.Type; import java.nio.charset.Charset; import java.util.Properties; /** * @author MrBird */ public class PropertiesHttpMessageConverter extends AbstractGenericHttpMessageConverter { public PropertiesHttpMessageConverter() { super(new MediaType("text", "properties")); } @Override protected void writeInternal(Properties properties, Type type, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException { // 获取请求头 HttpHeaders headers = outputMessage.getHeaders(); // 获取 content-type MediaType contentType = headers.getContentType(); // 获取编码 Charset charset = null; if (contentType != null) { charset = contentType.getCharset(); } charset = charset == null ? Charset.forName("UTF-8") : charset; // 获取请求体 OutputStream body = outputMessage.getBody(); OutputStreamWriter outputStreamWriter = new OutputStreamWriter(body, charset); properties.store(outputStreamWriter, "Serialized by PropertiesHttpMessageConverter#writeInternal"); } @Override protected Properties readInternal(Class clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException { Properties properties = new Properties(); // 获取请求头 HttpHeaders headers = inputMessage.getHeaders(); // 获取 content-type MediaType contentType = headers.getContentType(); // 获取编码 Charset charset = null; if (contentType != null) { charset = contentType.getCharset(); } charset = charset == null ? Charset.forName("UTF-8") : charset; // 获取请求体 InputStream body = inputMessage.getBody(); InputStreamReader inputStreamReader = new InputStreamReader(body, charset); properties.load(inputStreamReader); return properties; } @Override public Properties read(Type type, Class contextClass, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException { return readInternal(null, inputMessage); } } ================================================ FILE: 47.Spring-Boot-Content-Negotiation/src/main/java/com/example/demo/handler/PropertiesHandlerMethodReturnValueHandler.java ================================================ package com.example.demo.handler; import org.springframework.core.MethodParameter; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.http.server.ServletServerHttpResponse; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.context.request.ServletWebRequest; import org.springframework.web.method.support.HandlerMethodReturnValueHandler; import org.springframework.web.method.support.ModelAndViewContainer; import javax.servlet.http.HttpServletResponse; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.nio.charset.Charset; import java.util.Properties; /** * @author MrBird */ public class PropertiesHandlerMethodReturnValueHandler implements HandlerMethodReturnValueHandler { @Override public boolean supportsReturnType(MethodParameter returnType) { return Properties.class.equals(returnType.getMethod().getReturnType()); } @Override public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { Properties properties = (Properties) returnValue; ServletWebRequest servletWebRequest = (ServletWebRequest) webRequest; HttpServletResponse response = servletWebRequest.getResponse(); ServletServerHttpResponse servletServerHttpResponse = new ServletServerHttpResponse(response); // 获取请求头 HttpHeaders headers = servletServerHttpResponse.getHeaders(); MediaType contentType = headers.getContentType(); // 获取编码 Charset charset = null; if (contentType != null) { charset = contentType.getCharset(); } charset = charset == null ? Charset.forName("UTF-8") : charset; // 获取请求体 OutputStream body = servletServerHttpResponse.getBody(); OutputStreamWriter outputStreamWriter = new OutputStreamWriter(body, charset); properties.store(outputStreamWriter, "Serialized by PropertiesHandlerMethodReturnValueHandler#handleReturnValue"); // 告诉 Spring MVC 请求已经处理完毕 mavContainer.setRequestHandled(true); } } ================================================ FILE: 47.Spring-Boot-Content-Negotiation/src/main/java/com/example/demo/resolver/PropertiesHandlerMethodArgumentResolver.java ================================================ package com.example.demo.resolver; import org.springframework.core.MethodParameter; import org.springframework.http.MediaType; import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.context.request.ServletWebRequest; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.method.support.ModelAndViewContainer; import javax.servlet.http.HttpServletRequest; import java.io.InputStream; import java.io.InputStreamReader; import java.nio.charset.Charset; import java.util.Properties; /** * @author MrBird */ public class PropertiesHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver { @Override public boolean supportsParameter(MethodParameter parameter) { return Properties.class.equals(parameter.getParameterType()); } @Override public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { ServletWebRequest servletWebRequest = (ServletWebRequest) webRequest; HttpServletRequest request = servletWebRequest.getRequest(); String contentType = request.getHeader("Content-Type"); MediaType mediaType = MediaType.parseMediaType(contentType); // 获取编码 Charset charset = mediaType.getCharset() == null ? Charset.forName("UTF-8") : mediaType.getCharset(); // 获取输入流 InputStream inputStream = request.getInputStream(); InputStreamReader inputStreamReader = new InputStreamReader(inputStream, charset); // 输入流转换为 Properties Properties properties = new Properties(); properties.load(inputStreamReader); return properties; } } ================================================ FILE: 47.Spring-Boot-Content-Negotiation/src/main/resources/application.properties ================================================ ================================================ FILE: 47.Spring-Boot-Content-Negotiation/src/test/java/com/example/demo/DemoApplicationTests.java ================================================ package com.example.demo; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) @SpringBootTest public class DemoApplicationTests { @Test public void contextLoads() { } } ================================================ FILE: 48.Spring-Boot-CORS-Support/pom.xml ================================================ 4.0.0 org.springframework.boot spring-boot-starter-parent 2.1.0.RELEASE com.example demo 0.0.1-SNAPSHOT demo Demo project for Spring Boot 1.8 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-thymeleaf org.springframework.boot spring-boot-starter-test test org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 48.Spring-Boot-CORS-Support/src/main/java/com/example/demo/DemoApplication.java ================================================ package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ================================================ FILE: 48.Spring-Boot-CORS-Support/src/main/java/com/example/demo/config/WebConfigurer.java ================================================ package com.example.demo.config; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.filter.CorsFilter; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; /** * @author MrBird */ @Configuration public class WebConfigurer implements WebMvcConfigurer { // @Override // public void addCorsMappings(CorsRegistry registry) { // registry.addMapping("/**") // .allowedOrigins("*") // .allowedMethods("GET"); // } @Bean public FilterRegistrationBean corsFilter() { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); CorsConfiguration config = new CorsConfiguration(); config.setAllowCredentials(true); config.addAllowedOrigin("*"); source.registerCorsConfiguration("/**", config); FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source)); bean.setOrder(0); return bean; } } ================================================ FILE: 48.Spring-Boot-CORS-Support/src/main/java/com/example/demo/controller/TestController.java ================================================ package com.example.demo.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; /** * @author MrBird */ @Controller public class TestController { @RequestMapping("index") public String index() { return "index"; } @RequestMapping("hello") @ResponseBody // @CrossOrigin(value = "*") public String hello() { return "hello"; } } ================================================ FILE: 48.Spring-Boot-CORS-Support/src/main/resources/application.properties ================================================ ================================================ FILE: 48.Spring-Boot-CORS-Support/src/main/resources/templates/index.html ================================================ 跨域测试
================================================ FILE: 48.Spring-Boot-CORS-Support/src/test/java/com/example/demo/DemoApplicationTests.java ================================================ package com.example.demo; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) @SpringBootTest public class DemoApplicationTests { @Test public void contextLoads() { } } ================================================ FILE: 49.Spring-Boot-Async/pom.xml ================================================ 4.0.0 org.springframework.boot spring-boot-starter-parent 2.1.0.RELEASE com.example demo 0.0.1-SNAPSHOT demo Demo project for Spring Boot 1.8 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test test org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 49.Spring-Boot-Async/src/main/java/com/example/demo/DemoApplication.java ================================================ package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.scheduling.annotation.EnableAsync; @SpringBootApplication @EnableAsync public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ================================================ FILE: 49.Spring-Boot-Async/src/main/java/com/example/demo/config/AsyncPoolConfig.java ================================================ package com.example.demo.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import java.util.concurrent.ThreadPoolExecutor; /** * @author MrBird */ @Configuration public class AsyncPoolConfig { @Bean public ThreadPoolTaskExecutor asyncThreadPoolTaskExecutor(){ ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(20); executor.setMaxPoolSize(200); executor.setQueueCapacity(25); executor.setKeepAliveSeconds(200); executor.setThreadNamePrefix("asyncThread"); executor.setWaitForTasksToCompleteOnShutdown(true); executor.setAwaitTerminationSeconds(60); executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); executor.initialize(); return executor; } } ================================================ FILE: 49.Spring-Boot-Async/src/main/java/com/example/demo/controller/TestController.java ================================================ package com.example.demo.controller; import com.example.demo.service.TestService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; /** * @author MrBird */ @RestController public class TestController { private Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired private TestService testService; @GetMapping("async") public String testAsync() throws Exception { long start = System.currentTimeMillis(); logger.info("异步方法开始"); Future stringFuture = testService.asyncMethod(); String result = stringFuture.get(60, TimeUnit.SECONDS); logger.info("异步方法返回值:{}", result); logger.info("异步方法结束"); long end = System.currentTimeMillis(); logger.info("总耗时:{} ms", end - start); return stringFuture.get(); } @GetMapping("sync") public void testSync() { long start = System.currentTimeMillis(); logger.info("同步方法开始"); testService.syncMethod(); logger.info("同步方法结束"); long end = System.currentTimeMillis(); logger.info("总耗时:{} ms", end - start); } } ================================================ FILE: 49.Spring-Boot-Async/src/main/java/com/example/demo/service/TestService.java ================================================ package com.example.demo.service; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.AsyncResult; import org.springframework.stereotype.Service; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; /** * @author MrBird */ @Service public class TestService { private Logger logger = LoggerFactory.getLogger(this.getClass()); @Async("asyncThreadPoolTaskExecutor") // @Async public Future asyncMethod() { sleep(); logger.info("异步方法内部线程名称:{}", Thread.currentThread().getName()); return new AsyncResult<>("hello async"); } public void syncMethod() { sleep(); } private void sleep() { try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } } } ================================================ FILE: 49.Spring-Boot-Async/src/main/resources/application.properties ================================================ ================================================ FILE: 49.Spring-Boot-Async/src/test/java/com/example/demo/DemoApplicationTests.java ================================================ package com.example.demo; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) @SpringBootTest public class DemoApplicationTests { @Test public void contextLoads() { } } ================================================ FILE: 50.Spring-Regist-Bean/pom.xml ================================================ 4.0.0 org.springframework.boot spring-boot-starter-parent 2.1.0.RELEASE cc.mrbird demo 0.0.1-SNAPSHOT demo Demo project for Spring Boot 1.8 org.springframework.boot spring-boot-starter org.projectlombok lombok true org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 50.Spring-Regist-Bean/src/main/java/cc/mrbird/DemoApplication.java ================================================ package cc.mrbird; import cc.mrbird.demo.config.WebConfig; import cc.mrbird.demo.service.CalculateService; import org.springframework.boot.SpringApplication; import org.springframework.boot.WebApplicationType; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.context.ApplicationContext; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import java.util.Arrays; @SpringBootApplication public class DemoApplication { public static void main(String[] args) { ConfigurableApplicationContext context1 = new SpringApplicationBuilder(DemoApplication.class) .web(WebApplicationType.NONE) .profiles("java7") .run(args); // 返回 IOC 容器,使用注解配置,传入配置类 ApplicationContext context = new AnnotationConfigApplicationContext(WebConfig.class); System.out.println("容器创建完毕"); // User user = context.getBean(User.class); // System.out.println(user); // 查看 User 这个类在 Spring 容器中叫啥玩意 // String[] beanNames = context.getBeanNamesForType(User.class); // Arrays.stream(beanNames).forEach(System.out::println); // 查看基于注解的 IOC容器中所有组件名称 String[] beanNames = context.getBeanDefinitionNames(); Arrays.stream(beanNames).forEach(System.out::println); // 组件的作用域 // Object user1 = context.getBean("user"); // Object user2 = context.getBean("user"); // System.out.println(user1 == user2); // 测试懒加载 // Object user1 = context.getBean("user"); // Object user2 = context.getBean("user"); // 测试 Profile CalculateService service = context1.getBean(CalculateService.class); System.out.println("求合结果: " + service.sum(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)); // FactoryBean测试 Object cherry = context.getBean("cherryFactoryBean"); System.out.println(cherry.getClass()); Object cherryFactoryBean = context.getBean("&cherryFactoryBean"); System.out.println(cherryFactoryBean.getClass()); } } ================================================ FILE: 50.Spring-Regist-Bean/src/main/java/cc/mrbird/demo/condition/MyCondition.java ================================================ package cc.mrbird.demo.condition; import org.springframework.context.annotation.Condition; import org.springframework.context.annotation.ConditionContext; import org.springframework.core.type.AnnotatedTypeMetadata; /** * @author MrBird */ public class MyCondition implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { String osName = context.getEnvironment().getProperty("os.name"); return osName != null && osName.contains("Windows"); } } ================================================ FILE: 50.Spring-Regist-Bean/src/main/java/cc/mrbird/demo/config/WebConfig.java ================================================ package cc.mrbird.demo.config; import cc.mrbird.demo.condition.MyCondition; import cc.mrbird.demo.domain.Hello; import cc.mrbird.demo.domain.User; import cc.mrbird.demo.factory.CherryFactoryBean; import cc.mrbird.demo.filter.MyTypeFilter; import cc.mrbird.demo.register.MyImportBeanDefinitionRegistrar; import cc.mrbird.demo.selector.MyImportSelector; import lombok.Builder; import org.springframework.context.annotation.*; import org.springframework.context.annotation.ComponentScan.Filter; import org.springframework.stereotype.Controller; import org.springframework.stereotype.Repository; import org.springframework.stereotype.Service; /** * @author MrBird */ @Configuration // @ComponentScan(value = "cc.mrbird.demo" // , excludeFilters = { // @Filter(type = FilterType.ANNOTATION, // classes = {Controller.class, Repository.class}), // @Filter(type = FilterType.ASSIGNABLE_TYPE, classes = User.class) // @Filter(type = FilterType.CUSTOM, classes = MyTypeFilter.class) // } // includeFilters = { // @Filter(type = FilterType.ANNOTATION, classes = Service.class) // }, useDefaultFilters = false // ) @Import({Hello.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class}) public class WebConfig { @Bean // @Conditional(MyCondition.class) // @Lazy // @Scope("prototype") public User user() { System.out.println("往IOC容器中注册user bean"); return new User("mrbird", 18); } @Bean public CherryFactoryBean cherryFactoryBean() { return new CherryFactoryBean(); } } ================================================ FILE: 50.Spring-Regist-Bean/src/main/java/cc/mrbird/demo/controller/UserController.java ================================================ package cc.mrbird.demo.controller; import org.springframework.stereotype.Controller; /** * @author MrBird */ @Controller public class UserController { } ================================================ FILE: 50.Spring-Regist-Bean/src/main/java/cc/mrbird/demo/dao/UserMapper.java ================================================ package cc.mrbird.demo.dao; import org.springframework.stereotype.Repository; /** * @author MrBird */ @Repository public class UserMapper { } ================================================ FILE: 50.Spring-Regist-Bean/src/main/java/cc/mrbird/demo/domain/Apple.java ================================================ package cc.mrbird.demo.domain; /** * @author MrBird */ public class Apple { } ================================================ FILE: 50.Spring-Regist-Bean/src/main/java/cc/mrbird/demo/domain/Banana.java ================================================ package cc.mrbird.demo.domain; /** * @author MrBird */ public class Banana { } ================================================ FILE: 50.Spring-Regist-Bean/src/main/java/cc/mrbird/demo/domain/Cherry.java ================================================ package cc.mrbird.demo.domain; /** * @author MrBird */ public class Cherry { } ================================================ FILE: 50.Spring-Regist-Bean/src/main/java/cc/mrbird/demo/domain/Hello.java ================================================ package cc.mrbird.demo.domain; /** * @author MrBird */ public class Hello { } ================================================ FILE: 50.Spring-Regist-Bean/src/main/java/cc/mrbird/demo/domain/Strawberry.java ================================================ package cc.mrbird.demo.domain; /** * @author MrBird */ public class Strawberry { } ================================================ FILE: 50.Spring-Regist-Bean/src/main/java/cc/mrbird/demo/domain/User.java ================================================ package cc.mrbird.demo.domain; import lombok.*; import org.springframework.stereotype.Component; /** * @author MrBird */ @ToString @AllArgsConstructor @NoArgsConstructor @Data // @Component public class User { private String name; private Integer age; } ================================================ FILE: 50.Spring-Regist-Bean/src/main/java/cc/mrbird/demo/domain/UserDetail.java ================================================ package cc.mrbird.demo.domain; import org.springframework.stereotype.Component; /** * @author MrBird */ // @Component public class UserDetail extends User { private int sex; } ================================================ FILE: 50.Spring-Regist-Bean/src/main/java/cc/mrbird/demo/domain/Watermelon.java ================================================ package cc.mrbird.demo.domain; /** * @author MrBird */ public class Watermelon { } ================================================ FILE: 50.Spring-Regist-Bean/src/main/java/cc/mrbird/demo/factory/CherryFactoryBean.java ================================================ package cc.mrbird.demo.factory; import cc.mrbird.demo.domain.Cherry; import org.springframework.beans.factory.FactoryBean; /** * @author MrBird */ public class CherryFactoryBean implements FactoryBean { @Override public Cherry getObject() { return new Cherry(); } @Override public Class getObjectType() { return Cherry.class; } @Override public boolean isSingleton() { return false; } } ================================================ FILE: 50.Spring-Regist-Bean/src/main/java/cc/mrbird/demo/filter/MyTypeFilter.java ================================================ package cc.mrbird.demo.filter; import org.springframework.core.io.Resource; import org.springframework.core.type.AnnotationMetadata; import org.springframework.core.type.ClassMetadata; import org.springframework.core.type.classreading.MetadataReader; import org.springframework.core.type.classreading.MetadataReaderFactory; import org.springframework.core.type.filter.TypeFilter; import org.springframework.util.StringUtils; import java.io.IOException; /** * @author MrBird */ public class MyTypeFilter implements TypeFilter { @Override public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) { // 获取当前正在扫描的类的注解信息 AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata(); // 获取当前正在扫描的类的类信息 ClassMetadata classMetadata = metadataReader.getClassMetadata(); // 获取当前正在扫描的类的路径等信息 Resource resource = metadataReader.getResource(); String className = classMetadata.getClassName(); return StringUtils.hasText("er"); } } ================================================ FILE: 50.Spring-Regist-Bean/src/main/java/cc/mrbird/demo/register/MyImportBeanDefinitionRegistrar.java ================================================ package cc.mrbird.demo.register; import cc.mrbird.demo.domain.Strawberry; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.core.type.AnnotationMetadata; /** * @author MrBird */ public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { final String beanName = "strawberry"; boolean contain = registry.containsBeanDefinition(beanName); if (!contain) { RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Strawberry.class); registry.registerBeanDefinition(beanName, rootBeanDefinition); } } } ================================================ FILE: 50.Spring-Regist-Bean/src/main/java/cc/mrbird/demo/selector/MyImportSelector.java ================================================ package cc.mrbird.demo.selector; import org.springframework.context.annotation.ImportSelector; import org.springframework.core.type.AnnotationMetadata; /** * @author MrBird */ public class MyImportSelector implements ImportSelector { @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) { return new String[]{ "cc.mrbird.demo.domain.Apple", "cc.mrbird.demo.domain.Banana", "cc.mrbird.demo.domain.Watermelon" }; } } ================================================ FILE: 50.Spring-Regist-Bean/src/main/java/cc/mrbird/demo/service/CalculateService.java ================================================ package cc.mrbird.demo.service; /** * @author MrBird */ public interface CalculateService { Integer sum(Integer... value); } ================================================ FILE: 50.Spring-Regist-Bean/src/main/java/cc/mrbird/demo/service/UserService.java ================================================ package cc.mrbird.demo.service; import org.springframework.stereotype.Service; /** * @author MrBird */ @Service public class UserService { } ================================================ FILE: 50.Spring-Regist-Bean/src/main/java/cc/mrbird/demo/service/impl/Java7CalculateServiceImpl.java ================================================ package cc.mrbird.demo.service.impl; import cc.mrbird.demo.service.CalculateService; import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Service; /** * @author MrBird */ @Service @Profile("java7") public class Java7CalculateServiceImpl implements CalculateService { @Override public Integer sum(Integer... value) { System.out.println("Java 7环境下执行"); int result = 0; for (int i = 0; i <= value.length; i++) { result += i; } return result; } } ================================================ FILE: 50.Spring-Regist-Bean/src/main/java/cc/mrbird/demo/service/impl/Java8CalculateServiceImpl.java ================================================ package cc.mrbird.demo.service.impl; import cc.mrbird.demo.service.CalculateService; import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Service; import java.util.Arrays; /** * @author MrBird */ @Service @Profile("java8") public class Java8CalculateServiceImpl implements CalculateService { @Override public Integer sum(Integer... value) { System.out.println("Java 8环境下执行"); return Arrays.stream(value).reduce(0, Integer::sum); } } ================================================ FILE: 50.Spring-Regist-Bean/src/main/resources/application.properties ================================================ ================================================ FILE: 51.Spring-Bean-Lifecycle/pom.xml ================================================ 4.0.0 org.springframework.boot spring-boot-starter-parent 2.1.0.RELEASE cc.mrbird demo 0.0.1-SNAPSHOT demo Demo project for Spring Boot 1.8 org.springframework.boot spring-boot-starter org.projectlombok lombok true org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 51.Spring-Bean-Lifecycle/src/main/java/cc/mrbird/DemoApplication.java ================================================ package cc.mrbird; import cc.mrbird.demo.config.WebConfig; import cc.mrbird.demo.domain.User; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.AnnotationConfigApplicationContext; @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); // 返回 IOC 容器,使用注解配置,传入配置类 AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(WebConfig.class); System.out.println("容器创建完毕"); // User user = context.getBean(User.class); // 关闭 IOC 容器 context.close(); } } ================================================ FILE: 51.Spring-Bean-Lifecycle/src/main/java/cc/mrbird/demo/config/MyBeanPostProcessor.java ================================================ package cc.mrbird.demo.config; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.lang.Nullable; /** * @author MrBird */ public class MyBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println(beanName + " 初始化之前调用"); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println(beanName + " 初始化之后调用"); return bean; } } ================================================ FILE: 51.Spring-Bean-Lifecycle/src/main/java/cc/mrbird/demo/config/WebConfig.java ================================================ package cc.mrbird.demo.config; import cc.mrbird.demo.domain.Bird; import cc.mrbird.demo.domain.Fish; import cc.mrbird.demo.domain.User; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Scope; /** * @author MrBird */ @Configuration public class WebConfig { // @Scope("prototype") // @Bean(initMethod = "init", destroyMethod = "destory") // public User user() { // return new User(); // } // @Bean // public Bird bird() { // return new Bird(); // } @Bean public Fish fish(){ return new Fish(); } @Bean public MyBeanPostProcessor myBeanPostProcessor () { return new MyBeanPostProcessor(); } } ================================================ FILE: 51.Spring-Bean-Lifecycle/src/main/java/cc/mrbird/demo/domain/Bird.java ================================================ package cc.mrbird.demo.domain; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; /** * @author MrBird */ public class Bird implements InitializingBean, DisposableBean { public Bird() { System.out.println("调用无参构造器创建Bird"); } @Override public void destroy() { System.out.println("销毁Bird"); } @Override public void afterPropertiesSet() { System.out.println("初始化Bird"); } } ================================================ FILE: 51.Spring-Bean-Lifecycle/src/main/java/cc/mrbird/demo/domain/Fish.java ================================================ package cc.mrbird.demo.domain; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; /** * @author MrBird */ public class Fish { public Fish() { System.out.println("调用无参构造器创建Fish"); } @PostConstruct public void init() { System.out.println("初始化Fish"); } @PreDestroy public void destory() { System.out.println("销毁Fish"); } } ================================================ FILE: 51.Spring-Bean-Lifecycle/src/main/java/cc/mrbird/demo/domain/User.java ================================================ package cc.mrbird.demo.domain; /** * @author MrBird */ public class User { public User() { System.out.println("调用无参构造器创建User"); } public void init() { System.out.println("初始化User"); } public void destory() { System.out.println("销毁User"); } } ================================================ FILE: 51.Spring-Bean-Lifecycle/src/main/resources/application.properties ================================================ ================================================ FILE: 52.Dubbo-OPS-Mointor/spring-boot-dubbo-applicaiton/common-api/pom.xml ================================================ dubbo-boot cc.mrbird 1.0 4.0.0 common-api ================================================ FILE: 52.Dubbo-OPS-Mointor/spring-boot-dubbo-applicaiton/common-api/src/main/java/cc/mrbird/common/api/HelloService.java ================================================ package cc.mrbird.common.api; public interface HelloService { String hello(String message); } ================================================ FILE: 52.Dubbo-OPS-Mointor/spring-boot-dubbo-applicaiton/pom.xml ================================================ 4.0.0 cc.mrbird dubbo-boot pom 1.0 dubbo-boot Spring Boot-Dubbo-ZooKeeper common-api server-provider server-consumer org.springframework.boot spring-boot-starter-parent 2.0.4.RELEASE UTF-8 UTF-8 1.8 1.0 org.springframework.boot spring-boot-starter-web com.alibaba.boot dubbo-spring-boot-starter 0.2.0 org.apache.zookeeper zookeeper 3.4.8 com.101tec zkclient 0.10 org.apache.maven.plugins maven-compiler-plugin ${java.version} ${java.version} ${project.build.sourceEncoding} ================================================ FILE: 52.Dubbo-OPS-Mointor/spring-boot-dubbo-applicaiton/server-consumer/pom.xml ================================================ dubbo-boot cc.mrbird 1.0 4.0.0 server-consumer cc.mrbird common-api ${project.version} ================================================ FILE: 52.Dubbo-OPS-Mointor/spring-boot-dubbo-applicaiton/server-consumer/src/main/java/cc/mrbird/ConsumerApplicaiton.java ================================================ package cc.mrbird; import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @EnableDubbo @SpringBootApplication public class ConsumerApplicaiton { public static void main(String[] args) { SpringApplication.run(ConsumerApplicaiton.class, args); } } ================================================ FILE: 52.Dubbo-OPS-Mointor/spring-boot-dubbo-applicaiton/server-consumer/src/main/java/cc/mrbird/consumer/controller/HelloController.java ================================================ package cc.mrbird.consumer.controller; import cc.mrbird.common.api.HelloService; import com.alibaba.dubbo.config.annotation.Reference; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; @RestController public class HelloController { @Reference private HelloService helloService; @GetMapping("/hello/{message}") public String hello(@PathVariable String message) { return this.helloService.hello(message); } } ================================================ FILE: 52.Dubbo-OPS-Mointor/spring-boot-dubbo-applicaiton/server-consumer/src/main/resources/application.yml ================================================ server: port: 8081 dubbo: application: # 服务名称,保持唯一 name: server-consumer # zookeeper地址,用于从中获取注册的服务 registry: address: zookeeper://127.0.0.1:2181 protocol: # dubbo协议,固定写法 name: dubbo monitor: protocol: registry ================================================ FILE: 52.Dubbo-OPS-Mointor/spring-boot-dubbo-applicaiton/server-provider/pom.xml ================================================ dubbo-boot cc.mrbird 1.0 4.0.0 server-provider cc.mrbird common-api ${project.version} ================================================ FILE: 52.Dubbo-OPS-Mointor/spring-boot-dubbo-applicaiton/server-provider/src/main/java/cc/mrbird/ProviderApplicaiton.java ================================================ package cc.mrbird; import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @EnableDubbo @SpringBootApplication public class ProviderApplicaiton { public static void main(String[] args) { SpringApplication.run(ProviderApplicaiton.class, args); System.out.println("complete"); } } ================================================ FILE: 52.Dubbo-OPS-Mointor/spring-boot-dubbo-applicaiton/server-provider/src/main/java/cc/mrbird/provider/service/HelloServiceImpl.java ================================================ package cc.mrbird.provider.service; import cc.mrbird.common.api.HelloService; import com.alibaba.dubbo.config.annotation.Service; import org.springframework.stereotype.Component; @Service(interfaceClass = HelloService.class) @Component public class HelloServiceImpl implements HelloService { @Override public String hello(String message) { return "hello," + message; } } ================================================ FILE: 52.Dubbo-OPS-Mointor/spring-boot-dubbo-applicaiton/server-provider/src/main/resources/application.yml ================================================ server: port: 8080 dubbo: application: # 服务名称,保持唯一 name: server-provider # zookeeper地址,用于向其注册服务 registry: address: zookeeper://127.0.0.1:2181 #暴露服务方式 protocol: # dubbo协议,固定写法 name: dubbo # 暴露服务端口 (默认是20880,不同的服务提供者端口不能重复) port: 20880 monitor: protocol: registry ================================================ FILE: 53.Dubbo-High-Availability/common-api/pom.xml ================================================ dubbo-boot cc.mrbird 1.0 4.0.0 common-api ================================================ FILE: 53.Dubbo-High-Availability/common-api/src/main/java/cc/mrbird/common/api/HelloService.java ================================================ package cc.mrbird.common.api; public interface HelloService { String hello(String message); } ================================================ FILE: 53.Dubbo-High-Availability/pom.xml ================================================ 4.0.0 cc.mrbird dubbo-boot pom 1.0 dubbo-boot Spring Boot-Dubbo-ZooKeeper common-api server-provider server-consumer org.springframework.boot spring-boot-starter-parent 2.0.4.RELEASE UTF-8 UTF-8 1.8 1.0 org.springframework.boot spring-boot-starter-web com.alibaba.boot dubbo-spring-boot-starter 0.2.0 org.apache.zookeeper zookeeper 3.4.8 com.101tec zkclient 0.10 org.apache.maven.plugins maven-compiler-plugin ${java.version} ${java.version} ${project.build.sourceEncoding} ================================================ FILE: 53.Dubbo-High-Availability/server-consumer/pom.xml ================================================ dubbo-boot cc.mrbird 1.0 4.0.0 server-consumer cc.mrbird common-api ${project.version} ================================================ FILE: 53.Dubbo-High-Availability/server-consumer/src/main/java/cc/mrbird/ConsumerApplicaiton.java ================================================ package cc.mrbird; import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @EnableDubbo @SpringBootApplication public class ConsumerApplicaiton { public static void main(String[] args) { SpringApplication.run(ConsumerApplicaiton.class, args); } } ================================================ FILE: 53.Dubbo-High-Availability/server-consumer/src/main/java/cc/mrbird/consumer/controller/HelloController.java ================================================ package cc.mrbird.consumer.controller; import cc.mrbird.common.api.HelloService; import com.alibaba.dubbo.config.annotation.Reference; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; @RestController public class HelloController { // @Reference(url = "http://127.0.0.1:8080") // @Reference(loadbalance = RoundRobinLoadBalance.NAME) @Reference(timeout = 1000) private HelloService helloService; @GetMapping("/hello/{message}") public String hello(@PathVariable String message) { return this.helloService.hello(message); } } ================================================ FILE: 53.Dubbo-High-Availability/server-consumer/src/main/resources/application.yml ================================================ server: port: 8081 dubbo: application: # 服务名称,保持唯一 name: server-consumer # zookeeper地址,用于从中获取注册的服务 registry: address: zookeeper://127.0.0.1:2181 protocol: # dubbo协议,固定写法 name: dubbo monitor: protocol: registry ================================================ FILE: 53.Dubbo-High-Availability/server-provider/pom.xml ================================================ dubbo-boot cc.mrbird 1.0 4.0.0 server-provider cc.mrbird common-api ${project.version} org.springframework.cloud spring-cloud-starter-netflix-hystrix 2.0.2.RELEASE ================================================ FILE: 53.Dubbo-High-Availability/server-provider/src/main/java/cc/mrbird/ProviderApplicaiton.java ================================================ package cc.mrbird; import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.hystrix.EnableHystrix; @EnableHystrix @EnableDubbo @SpringBootApplication public class ProviderApplicaiton { public static void main(String[] args) { SpringApplication.run(ProviderApplicaiton.class, args); System.out.println("complete"); } } ================================================ FILE: 53.Dubbo-High-Availability/server-provider/src/main/java/cc/mrbird/provider/service/HelloServiceImpl.java ================================================ package cc.mrbird.provider.service; import cc.mrbird.common.api.HelloService; import com.alibaba.dubbo.config.annotation.Service; import com.alibaba.dubbo.rpc.cluster.loadbalance.RoundRobinLoadBalance; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; import org.springframework.stereotype.Component; import java.util.concurrent.TimeUnit; @Service( interfaceClass = HelloService.class, weight = 100, loadbalance = RoundRobinLoadBalance.NAME) @Component public class HelloServiceImpl implements HelloService { @Override @HystrixCommand(fallbackMethod = "defaultHello") public String hello(String message) { System.out.println("调用 cc.mrbird.provider.service.HelloServiceImpl#hello"); // try { // TimeUnit.SECONDS.sleep(2); // } catch (InterruptedException e) { // e.printStackTrace(); // } String a = null; a.toString(); return "hello," + message; } public String defaultHello(String message) { return "hello anonymous"; } } ================================================ FILE: 53.Dubbo-High-Availability/server-provider/src/main/resources/application.yml ================================================ server: port: 8080 dubbo: application: # 服务名称,保持唯一 name: server-provider # zookeeper地址,用于向其注册服务 registry: address: zookeeper://127.0.0.1:2181 #暴露服务方式 protocol: # dubbo协议,固定写法 name: dubbo # 暴露服务端口 (默认是20880,不同的服务提供者端口不能重复) port: 20880 monitor: protocol: registry ================================================ FILE: 54.Spring-Boot-Kafka/pom.xml ================================================ 4.0.0 org.springframework.boot spring-boot-starter-parent 2.1.3.RELEASE com.example demo 0.0.1-SNAPSHOT demo Demo project for Spring Boot 1.8 org.springframework.boot spring-boot-starter-web org.springframework.kafka spring-kafka org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 54.Spring-Boot-Kafka/src/main/java/com/example/demo/KafkaApplication.java ================================================ package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class KafkaApplication { public static void main(String[] args) { SpringApplication.run(KafkaApplication.class, args); } } ================================================ FILE: 54.Spring-Boot-Kafka/src/main/java/com/example/demo/config/KafkaConsumerConfig.java ================================================ package com.example.demo.config; import com.example.demo.domain.Message; import org.apache.kafka.clients.consumer.ConsumerConfig; import org.apache.kafka.common.serialization.StringDeserializer; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.kafka.annotation.EnableKafka; import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory; import org.springframework.kafka.core.ConsumerFactory; import org.springframework.kafka.core.DefaultKafkaConsumerFactory; import org.springframework.kafka.support.serializer.JsonDeserializer; import org.springframework.kafka.support.serializer.JsonSerializer; import java.util.HashMap; import java.util.Map; /** * @author MrBird */ @EnableKafka @Configuration public class KafkaConsumerConfig { @Value("${spring.kafka.bootstrap-servers}") private String bootstrapServers; @Value("${spring.kafka.consumer.group-id}") private String consumerGroupId; @Value("${spring.kafka.consumer.auto-offset-reset}") private String autoOffsetReset; @Bean public ConsumerFactory consumerFactory() { Map props = new HashMap<>(); props.put( ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers); props.put( ConsumerConfig.GROUP_ID_CONFIG, consumerGroupId); props.put( ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, autoOffsetReset); // props.put( // ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, // StringDeserializer.class); // props.put( // ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, // StringDeserializer.class); return new DefaultKafkaConsumerFactory<>( props, new StringDeserializer(), new JsonDeserializer<>(Message.class)); } @Bean public ConcurrentKafkaListenerContainerFactory kafkaListenerContainerFactory() { ConcurrentKafkaListenerContainerFactory factory = new ConcurrentKafkaListenerContainerFactory<>(); factory.setConsumerFactory(consumerFactory()); // factory.setRecordFilterStrategy( // r -> r.value().contains("fuck") // ); return factory; } } ================================================ FILE: 54.Spring-Boot-Kafka/src/main/java/com/example/demo/config/KafkaProducerConfig.java ================================================ package com.example.demo.config; import com.example.demo.domain.Message; import org.apache.kafka.clients.producer.ProducerConfig; import org.apache.kafka.common.serialization.StringSerializer; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.kafka.core.DefaultKafkaProducerFactory; import org.springframework.kafka.core.KafkaTemplate; import org.springframework.kafka.core.ProducerFactory; import org.springframework.kafka.support.serializer.JsonSerializer; import java.util.HashMap; import java.util.Map; /** * @author MrBird */ @Configuration public class KafkaProducerConfig { @Value("${spring.kafka.bootstrap-servers}") private String bootstrapServers; @Bean public ProducerFactory producerFactory() { Map configProps = new HashMap<>(); configProps.put( ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers); configProps.put( ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class); configProps.put( ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonSerializer.class); return new DefaultKafkaProducerFactory<>(configProps); } @Bean public KafkaTemplate kafkaTemplate() { return new KafkaTemplate<>(producerFactory()); } } ================================================ FILE: 54.Spring-Boot-Kafka/src/main/java/com/example/demo/controller/SendMessageController.java ================================================ package com.example.demo.controller; import com.example.demo.domain.Message; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.kafka.core.KafkaTemplate; import org.springframework.kafka.support.SendResult; import org.springframework.util.concurrent.ListenableFuture; import org.springframework.util.concurrent.ListenableFutureCallback; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; /** * @author MrBird */ @RestController public class SendMessageController { private Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired // private KafkaTemplate kafkaTemplate; private KafkaTemplate kafkaTemplate; // @GetMapping("send/{message}") // public void send(@PathVariable String message) { // this.kafkaTemplate.send("test", message); // ListenableFuture> future = this.kafkaTemplate.send("test", message); // future.addCallback(new ListenableFutureCallback>() { // @Override // public void onSuccess(SendResult result) { // logger.info("成功发送消息:{},offset=[{}]", message, result.getRecordMetadata().offset()); // } // // @Override // public void onFailure(Throwable ex) { // logger.error("消息:{} 发送失败,原因:{}", message, ex.getMessage()); // } // }); // } @GetMapping("send/{message}") public void sendMessage(@PathVariable String message) { this.kafkaTemplate.send("test", new Message("mrbird", message)); } } ================================================ FILE: 54.Spring-Boot-Kafka/src/main/java/com/example/demo/domain/Message.java ================================================ package com.example.demo.domain; import java.io.Serializable; import java.time.LocalTime; /** * @author MrBird */ public class Message implements Serializable { private static final long serialVersionUID = 6678420965611108427L; private String from; private String message; public Message() { } public Message(String from, String message) { this.from = from; this.message = message; } @Override public String toString() { return "Message{" + "from='" + from + '\'' + ", message='" + message + '\'' + '}'; } public String getFrom() { return from; } public void setFrom(String from) { this.from = from; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } } ================================================ FILE: 54.Spring-Boot-Kafka/src/main/java/com/example/demo/listener/KafkaMessageListener.java ================================================ package com.example.demo.listener; import com.example.demo.domain.Message; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.kafka.annotation.KafkaListener; import org.springframework.kafka.annotation.PartitionOffset; import org.springframework.kafka.annotation.TopicPartition; import org.springframework.kafka.support.KafkaHeaders; import org.springframework.messaging.handler.annotation.Header; import org.springframework.messaging.handler.annotation.Payload; import org.springframework.stereotype.Component; /** * @author MrBird */ @Component public class KafkaMessageListener { private Logger logger = LoggerFactory.getLogger(this.getClass()); // @KafkaListener(topics = "test", groupId = "test-consumer") // @KafkaListener(groupId = "test-consumer", // topicPartitions = @TopicPartition(topic = "test", // partitionOffsets = { // @PartitionOffset(partition = "0", initialOffset = "0") // })) // public void listen(@Payload String message, // @Header(KafkaHeaders.RECEIVED_PARTITION_ID) int partition) { // logger.info("接收消息: {},partition:{}", message, partition); // } @KafkaListener(topics = "test", groupId = "test-consumer") public void listen(Message message) { logger.info("接收消息: {}", message); } } ================================================ FILE: 54.Spring-Boot-Kafka/src/main/resources/application.yml ================================================ spring: kafka: bootstrap-servers: localhost:9092 consumer: group-id: test-consumer auto-offset-reset: latest ================================================ FILE: 55.Spring-Cloud-Consul/server-consumer/pom.xml ================================================ 4.0.0 org.springframework.boot spring-boot-starter-parent 2.0.2.RELEASE com.example server-consumer 1.0 server-consumer Demo project for Spring Boot 1.8 Finchley.RELEASE org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-actuator org.springframework.cloud spring-cloud-starter-consul-discovery org.springframework.cloud spring-cloud-dependencies ${spring-cloud.version} pom import org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 55.Spring-Cloud-Consul/server-consumer/src/main/java/com/example/demo/ServerConsumerApplication.java ================================================ package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; @EnableDiscoveryClient @SpringBootApplication public class ServerConsumerApplication { public static void main(String[] args) { SpringApplication.run(ServerConsumerApplication.class, args); } } ================================================ FILE: 55.Spring-Cloud-Consul/server-consumer/src/main/java/com/example/demo/TestController.java ================================================ package com.example.demo; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; import java.net.URI; import java.util.List; import java.util.stream.Collectors; /** * @author MrBird */ @RestController public class TestController { private Logger loggr = LoggerFactory.getLogger(this.getClass()); @Autowired private DiscoveryClient discoveryClient; @Autowired private LoadBalancerClient loadBalancerClient; private final RestTemplate restTemplate = new RestTemplate(); // @Autowired // private RestTemplate restTemplate; private static final String SERVER_ID = "server-provider"; @GetMapping("uri") public List getServerUris() { return this.discoveryClient.getInstances(SERVER_ID) .stream() .map(ServiceInstance::getUri).collect(Collectors.toList()); } @GetMapping("hello") public String hello() { ServiceInstance instance = loadBalancerClient.choose(SERVER_ID); String url = instance.getUri().toString() + "/hello"; loggr.info("remote server url:{}", url); return restTemplate.getForObject(url, String.class); } // @Bean // @LoadBalanced // public RestTemplate restTemplate() { // return new RestTemplate(); // } // @GetMapping("hello") // public String hello() { // String url = "http://" + SERVER_ID + "/hello"; // return restTemplate.getForObject(url, String.class); // } } ================================================ FILE: 55.Spring-Cloud-Consul/server-consumer/src/main/resources/application.yml ================================================ server: port: 9002 spring: application: name: server-consumer cloud: consul: host: 192.168.140.215 port: 8500 discovery: service-name: ${spring.application.name} ================================================ FILE: 55.Spring-Cloud-Consul/server-proivder/pom.xml ================================================ 4.0.0 org.springframework.boot spring-boot-starter-parent 2.0.2.RELEASE com.example server-provider 1.0 server-provider Demo project for Spring Boot 1.8 Finchley.RELEASE org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-actuator org.springframework.cloud spring-cloud-starter-consul-discovery org.springframework.cloud spring-cloud-dependencies ${spring-cloud.version} pom import org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 55.Spring-Cloud-Consul/server-proivder/src/main/java/com/example/demo/ServerProviderApplication.java ================================================ package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; @EnableDiscoveryClient @SpringBootApplication public class ServerProviderApplication { public static void main(String[] args) { SpringApplication.run(ServerProviderApplication.class, args); } } ================================================ FILE: 55.Spring-Cloud-Consul/server-proivder/src/main/java/com/example/demo/TestController.java ================================================ package com.example.demo; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; /** * @author MrBird */ @RestController public class TestController { private Logger logger = LoggerFactory.getLogger(this.getClass()); @GetMapping("check") private String check() { logger.info("health check"); return "ok"; } @GetMapping("hello") public String hello() { logger.info("hello"); return "hello from server provider"; } } ================================================ FILE: 55.Spring-Cloud-Consul/server-proivder/src/main/resources/application.yml ================================================ server: port: 9000 spring: application: name: server-provider cloud: consul: host: 192.168.140.215 port: 8500 discovery: health-check-interval: 10s service-name: ${spring.application.name} register-health-check: true health-check-path: /check ================================================ FILE: 56.Spring-Boot-MongoDB-crud/Mongo DB crud.postman_collection.json ================================================ { "info": { "_postman_id": "8fa1e028-3088-4d19-bb08-4d41b3802487", "name": "Mongo DB crud", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" }, "item": [ { "name": "createUser", "request": { "method": "POST", "header": [], "body": { "mode": "raw", "raw": "" }, "url": { "raw": "localhost:8080/user?name=mike&description=python developer&age=21", "host": [ "localhost" ], "port": "8080", "path": [ "user" ], "query": [ { "key": "name", "value": "mike" }, { "key": "description", "value": "python developer" }, { "key": "age", "value": "21" } ] } }, "response": [] }, { "name": "getUsers", "request": { "method": "GET", "header": [], "body": { "mode": "raw", "raw": "" }, "url": { "raw": "localhost:8080/user", "host": [ "localhost" ], "port": "8080", "path": [ "user" ] } }, "response": [] }, { "name": "getUser", "request": { "method": "GET", "header": [], "body": { "mode": "raw", "raw": "" }, "url": { "raw": "localhost:8080/user/5ca56280f08f0b6048fd470b", "host": [ "localhost" ], "port": "8080", "path": [ "user", "5ca56280f08f0b6048fd470b" ] } }, "response": [] }, { "name": "updateUser", "request": { "method": "PUT", "header": [], "body": { "mode": "raw", "raw": "" }, "url": { "raw": "localhost:8080/user/5ca40ee8f08f0b68cc06c001?id=5ca56280f08f0b6048fd470b&description=Java gosu&age=19", "host": [ "localhost" ], "port": "8080", "path": [ "user", "5ca40ee8f08f0b68cc06c001" ], "query": [ { "key": "id", "value": "5ca56280f08f0b6048fd470b" }, { "key": "description", "value": "Java gosu" }, { "key": "age", "value": "19" } ] } }, "response": [] }, { "name": "deleteUser", "request": { "method": "DELETE", "header": [], "body": { "mode": "raw", "raw": "" }, "url": { "raw": "localhost:8080/user/5ca56280f08f0b6048fd470b", "host": [ "localhost" ], "port": "8080", "path": [ "user", "5ca56280f08f0b6048fd470b" ] } }, "response": [] }, { "name": "getUsersStream", "request": { "method": "GET", "header": [], "body": { "mode": "raw", "raw": "" }, "url": { "raw": "localhost:8080/user/stream", "host": [ "localhost" ], "port": "8080", "path": [ "user", "stream" ] } }, "response": [] }, { "name": "getUserByAge", "request": { "method": "GET", "header": [], "body": { "mode": "raw", "raw": "" }, "url": { "raw": "localhost:8080/user/age/20/30", "host": [ "localhost" ], "port": "8080", "path": [ "user", "age", "20", "30" ] } }, "response": [] }, { "name": "getUserByName", "request": { "method": "GET", "header": [], "body": { "mode": "raw", "raw": "" }, "url": { "raw": "localhost:8080/user/name/mrbird", "host": [ "localhost" ], "port": "8080", "path": [ "user", "name", "mrbird" ] } }, "response": [] }, { "name": "getUserByDescription", "request": { "method": "GET", "header": [], "body": { "mode": "raw", "raw": "" }, "url": { "raw": "localhost:8080/user/description/ui", "host": [ "localhost" ], "port": "8080", "path": [ "user", "description", "ui" ] } }, "response": [] }, { "name": "getUserByCondition", "request": { "method": "GET", "header": [], "body": { "mode": "raw", "raw": "" }, "url": { "raw": "localhost:8080/user/condition?size=2&page=0", "host": [ "localhost" ], "port": "8080", "path": [ "user", "condition" ], "query": [ { "key": "name", "value": "mrbird", "disabled": true }, { "key": "description", "value": "r", "disabled": true }, { "key": "size", "value": "2" }, { "key": "page", "value": "0" } ] } }, "response": [] } ] } ================================================ FILE: 56.Spring-Boot-MongoDB-crud/pom.xml ================================================ 4.0.0 org.springframework.boot spring-boot-starter-parent 2.1.3.RELEASE com.example mongodb 0.0.1-SNAPSHOT mongodb Demo project for Spring Boot 1.8 org.springframework.boot spring-boot-starter-data-mongodb org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 56.Spring-Boot-MongoDB-crud/src/main/java/com/example/mongodb/MongodbApplication.java ================================================ package com.example.mongodb; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class MongodbApplication { public static void main(String[] args) { SpringApplication.run(MongodbApplication.class, args); } } ================================================ FILE: 56.Spring-Boot-MongoDB-crud/src/main/java/com/example/mongodb/controller/UserController.java ================================================ package com.example.mongodb.controller; import com.example.mongodb.domain.User; import com.example.mongodb.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.web.bind.annotation.*; import java.util.List; /** * @author MrBird */ @RestController @RequestMapping("user") public class UserController { @Autowired private UserService userService; @GetMapping public List getUsers() { return userService.getUsers(); } @PostMapping public User createUser(User user) { return userService.createUser(user); } @DeleteMapping("/{id}") public void deleteUser(@PathVariable String id) { userService.deleteUser(id); } @PutMapping("/{id}") public void updateUser(@PathVariable String id, User user) { userService.updateUser(id, user); } /** * 根据用户 id查找 * 存在返回,不存在返回 null */ @GetMapping("/{id}") public User getUser(@PathVariable String id) { return userService.getUser(id).orElse(null); } /** * 根据年龄段来查找 */ @GetMapping("/age/{from}/{to}") public List getUserByAge(@PathVariable Integer from, @PathVariable Integer to) { return userService.getUserByAge(from, to); } /** * 根据用户名查找 */ @GetMapping("/name/{name}") public List getUserByName(@PathVariable String name) { return userService.getUserByName(name); } /** * 根据用户描述模糊查找 */ @GetMapping("/description/{description}") public List getUserByDescription(@PathVariable String description) { return userService.getUserByDescription(description); } /** * 根据多个检索条件查询 */ @GetMapping("/condition") public Page getUserByCondition(int size, int page, User user) { return userService.getUserByCondition(size, page, user); } } ================================================ FILE: 56.Spring-Boot-MongoDB-crud/src/main/java/com/example/mongodb/dao/UserDao.java ================================================ package com.example.mongodb.dao; import com.example.mongodb.domain.User; import org.springframework.data.mongodb.repository.MongoRepository; import org.springframework.stereotype.Repository; import java.util.List; /** * @author MrBird */ @Repository public interface UserDao extends MongoRepository { /** * 根据年龄段来查找 * * @param from from * @param to to * @return List */ List findByAgeBetween(Integer from, Integer to); /** * 通过年龄段,用户名,描述(模糊查询) * * @param from from * @param to to * @param name name * @param description description * @return List */ List findByAgeBetweenAndNameEqualsAndDescriptionIsLike(Integer from, Integer to, String name, String description); /** * 更具描述来模糊查询用户 * * @param description 描述 * @return List */ List findByDescriptionIsLike(String description); /** * 通过用户名查询 * * @param name 用户名 * @return List */ List findByNameEquals(String name); } ================================================ FILE: 56.Spring-Boot-MongoDB-crud/src/main/java/com/example/mongodb/domain/User.java ================================================ package com.example.mongodb.domain; import org.springframework.data.annotation.Id; import org.springframework.data.annotation.Transient; import org.springframework.data.mongodb.core.mapping.Document; /** * @author MrBird */ @Document(collection = "user") public class User { @Id private String id; private String name; private Integer age; private String description; 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 Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } } ================================================ FILE: 56.Spring-Boot-MongoDB-crud/src/main/java/com/example/mongodb/service/UserService.java ================================================ package com.example.mongodb.service; import com.example.mongodb.dao.UserDao; import com.example.mongodb.domain.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.repository.support.PageableExecutionUtils; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; import java.util.List; import java.util.Optional; /** * @author MrBird */ @Service public class UserService { @Autowired private UserDao userDao; @Autowired private MongoTemplate template; public List getUsers() { return userDao.findAll(); } public Optional getUser(String id) { return this.userDao.findById(id); } /** * 新增和修改都是 save方法, * id 存在为修改,id 不存在为新增 */ public User createUser(User user) { user.setId(null); return userDao.save(user); } public void deleteUser(String id) { this.userDao.findById(id) .ifPresent(user -> this.userDao.delete(user)); } public void updateUser(String id, User user) { this.userDao.findById(id) .ifPresent( u -> { u.setName(user.getName()); u.setAge(user.getAge()); u.setDescription(user.getDescription()); this.userDao.save(u); } ); } public List getUserByAge(Integer from, Integer to) { return this.userDao.findByAgeBetween(from, to); } public List getUserByName(String name) { return this.userDao.findByNameEquals(name); } public List getUserByDescription(String description) { return this.userDao.findByDescriptionIsLike(description); } public Page getUserByCondition(int size, int page, User user) { Query query = new Query(); Criteria criteria = new Criteria(); if (!StringUtils.isEmpty(user.getName())) { criteria.and("name").is(user.getName()); } if (!StringUtils.isEmpty(user.getDescription())) { criteria.and("description").regex(user.getDescription()); } query.addCriteria(criteria); Sort sort = new Sort(Sort.Direction.DESC, "age"); Pageable pageable = PageRequest.of(page, size, sort); List users = template.find(query.with(pageable), User.class); return PageableExecutionUtils.getPage(users, pageable, () -> template.count(query, User.class)); } } ================================================ FILE: 56.Spring-Boot-MongoDB-crud/src/main/resources/application.yml ================================================ spring: data: mongodb: host: localhost port: 27017 database: testdb ================================================ FILE: 57.Spring-Boot-WebFlux/async-servlet/src/AsyncServlet.java ================================================ import javax.servlet.AsyncContext; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import java.util.logging.Logger; /** * @author MrBird */ @WebServlet(urlPatterns = "/async", asyncSupported = true) public class AsyncServlet extends HttpServlet { private static final long serialVersionUID = 393375716683413545L; private Logger log = Logger.getLogger(AsyncServlet.class.getName()); @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) { long start = System.currentTimeMillis(); AsyncContext asyncContext = request.startAsync(); CompletableFuture.runAsync(() -> execute(asyncContext, asyncContext.getRequest(), asyncContext.getResponse())); log.info("总耗时:" + (System.currentTimeMillis() - start) + "ms"); } private void execute(AsyncContext asyncContext, ServletRequest request, ServletResponse response) { try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } try { response.getWriter().append("hello"); } catch (IOException e) { e.printStackTrace(); } asyncContext.complete(); } } ================================================ FILE: 57.Spring-Boot-WebFlux/async-servlet/src/SyncServlet.java ================================================ import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.concurrent.TimeUnit; import java.util.logging.Logger; /** * @author MrBird */ @WebServlet(urlPatterns = "/sync") public class SyncServlet extends HttpServlet { private static final long serialVersionUID = 7583536145022393360L; private Logger log = Logger.getLogger(SyncServlet.class.getName()); @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) { long start = System.currentTimeMillis(); this.execute(request, response); log.info("总耗时:" + (System.currentTimeMillis() - start) + "ms"); } private void execute(HttpServletRequest request, HttpServletResponse response) { try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } try { response.getWriter().append("hello"); } catch (IOException e) { e.printStackTrace(); } } } ================================================ FILE: 57.Spring-Boot-WebFlux/async-servlet/web/WEB-INF/web.xml ================================================ ================================================ FILE: 57.Spring-Boot-WebFlux/async-servlet/web/index.html ================================================ hello ================================================ FILE: 57.Spring-Boot-WebFlux/webflux/pom.xml ================================================ 4.0.0 org.springframework.boot spring-boot-starter-parent 2.1.3.RELEASE com.example webflux 0.0.1-SNAPSHOT webflux Demo project for Spring Boot 1.8 org.springframework.boot spring-boot-starter-webflux org.springframework.boot spring-boot-starter-thymeleaf org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 57.Spring-Boot-WebFlux/webflux/src/main/java/com/example/webflux/FluxTest.java ================================================ package com.example.webflux; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import java.time.Duration; import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.Random; /** * @author MrBird */ public class FluxTest { public static void main(String[] args) throws InterruptedException { Flux.just("Hello", "World").subscribe(System.out::println); Flux.fromArray(new Integer[]{1, 2, 3}).subscribe(System.out::println); Flux.empty().subscribe(System.out::println); Flux.range(1, 4).subscribe(System.out::println); // Flux.interval(Duration.of(1, ChronoUnit.SECONDS)).subscribe(System.out::println); Flux.generate(sink -> { sink.next("Hello"); sink.complete(); }).subscribe(System.out::println); final Random random = new Random(); Flux.generate(ArrayList::new, (list, sink) -> { int value = random.nextInt(100); list.add(value); sink.next(value); if (list.size() == 10) { sink.complete(); } return list; }).subscribe(System.out::println); Flux.create(sink -> { for (int i = 0; i < 10; i++) { sink.next(i); } sink.complete(); }).subscribe(System.out::println); Flux.range(1, 10).filter(i -> i % 2 == 0).subscribe(System.out::println); Flux.range(1, 20).take(10).subscribe(System.out::println); Flux.range(1, 20).takeLast(10).subscribe(System.out::println); Flux.range(1, 20).takeWhile(i -> i < 10).subscribe(System.out::println); Flux.range(1, 20).takeUntil(i -> i == 10).subscribe(System.out::println); Flux.range(1, 10).reduce((x, y) -> x + y).subscribe(System.out::println); Flux.range(1, 10).reduceWith(() -> 10, (x, y) -> x + y).subscribe(System.out::println); Flux.merge( Flux.interval(Duration.of(500, ChronoUnit.MILLIS)).take(2), Flux.interval(Duration.of(500, ChronoUnit.MILLIS)).take(2) ).toStream().forEach(System.out::println); Flux.range(1, 100).buffer(20).subscribe(System.out::println); Flux.range(1, 10).bufferUntil(i -> i % 2 == 0).subscribe(System.out::println); Flux.range(1, 10).bufferWhile(i -> i % 2 == 0).subscribe(System.out::println); Flux.just("a", "b", "c", "d") .zipWith(Flux.just("e", "f", "g", "h", "i")) .subscribe(System.out::println); Flux.just("a", "b", "c", "d") .zipWith(Flux.just("e", "f", "g", "h", "i"), (s1, s2) -> String.format("%s-%s", s1, s2)) .subscribe(System.out::println); Flux.just(1, 2) .concatWith(Mono.error(new IllegalStateException())) .subscribe(System.out::println, System.err::println); Flux.just(1, 2) .concatWith(Mono.error(new IllegalStateException())) .onErrorReturn(0) .subscribe(System.out::println); Flux.just(1, 2) .concatWith(Mono.error(new IllegalArgumentException())) .onErrorResume(e -> { if (e instanceof IllegalStateException) { return Mono.just(0); } else if (e instanceof IllegalArgumentException) { return Mono.just(-1); } return Mono.empty(); }).subscribe(System.out::println); Thread.currentThread().join(20000); } } ================================================ FILE: 57.Spring-Boot-WebFlux/webflux/src/main/java/com/example/webflux/MonoFluxTest.java ================================================ package com.example.webflux; import java.util.concurrent.TimeUnit; import org.reactivestreams.Subscriber; import org.reactivestreams.Subscription; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; public class MonoFluxTest { public static void main(String[] args) { Subscriber subscriber = new Subscriber() { private Subscription subscription; @Override public void onSubscribe(Subscription subscription) { this.subscription = subscription; this.subscription.request(1); } @Override public void onNext(Integer item) { System.out.println("接受到数据: " + item); try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } this.subscription.request(1); } @Override public void onError(Throwable throwable) { throwable.printStackTrace(); this.subscription.cancel(); } @Override public void onComplete() { System.out.println("处理完了!"); } }; String[] strs = {"1", "2", "3"}; Flux.fromArray(strs).map(Integer::parseInt).subscribe(subscriber); Mono.fromSupplier(() -> 1).map(s -> s + 1).subscribe(subscriber); } } ================================================ FILE: 57.Spring-Boot-WebFlux/webflux/src/main/java/com/example/webflux/MonoTest.java ================================================ package com.example.webflux; import reactor.core.publisher.Mono; import java.util.Optional; /** * @author MrBird */ public class MonoTest { public static void main(String[] args) { Mono.just("are").subscribe(System.out::println); Mono.empty().subscribe(System.out::println); Mono.fromSupplier(() -> "you").subscribe(System.out::println); Mono.justOrEmpty(Optional.of("ok")).subscribe(System.out::println); Mono.create(sink -> sink.success("Hello")).subscribe(System.out::println); } } ================================================ FILE: 57.Spring-Boot-WebFlux/webflux/src/main/java/com/example/webflux/TestController.java ================================================ package com.example.webflux; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import java.util.concurrent.TimeUnit; import java.util.stream.IntStream; /** * @author MrBird */ @RestController public class TestController { // Mono 表示 0-1 个元素,Flux 0-N 个元素 private Logger logger = LoggerFactory.getLogger(this.getClass()); @GetMapping("sync") public String sync() { logger.info("sync method start"); String result = this.execute(); logger.info("sync method end"); return result; } @GetMapping("async/mono") public Mono asyncMono() { logger.info("async method start"); Mono result = Mono.fromSupplier(this::execute); logger.info("async method end"); return result; } // SSE(Server Sent Event) // https://developer.mozilla.org/zh-CN/docs/Server-sent_events/Using_server-sent_events // http://www.ruanyifeng.com/blog/2017/05/server-sent_events.html @GetMapping(value = "async/flux", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public Flux asyncFlux() { logger.info("async method start"); Flux result = Flux.fromStream(IntStream.range(1, 5).mapToObj(i -> { try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } return "int value:" + i; })); logger.info("async method end"); return result; } private String execute() { try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } return "hello"; } } ================================================ FILE: 57.Spring-Boot-WebFlux/webflux/src/main/java/com/example/webflux/ViewController.java ================================================ package com.example.webflux; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; /** * @author MrBird */ @Controller public class ViewController { @GetMapping("flux") public String flux() { return "flux"; } } ================================================ FILE: 57.Spring-Boot-WebFlux/webflux/src/main/java/com/example/webflux/WebfluxApplication.java ================================================ package com.example.webflux; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class WebfluxApplication { public static void main(String[] args) { SpringApplication.run(WebfluxApplication.class, args); } } ================================================ FILE: 57.Spring-Boot-WebFlux/webflux/src/main/resources/application.yml ================================================ ================================================ FILE: 57.Spring-Boot-WebFlux/webflux/src/main/resources/templates/flux.html ================================================ test sse ================================================ FILE: 58.Spring-Boot-WebFlux-crud/pom.xml ================================================ 4.0.0 org.springframework.boot spring-boot-starter-parent 2.1.3.RELEASE com.example webflux 0.0.1-SNAPSHOT webflux Demo project for Spring Boot 1.8 org.springframework.boot spring-boot-starter-webflux org.springframework.boot spring-boot-starter-data-mongodb-reactive org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 58.Spring-Boot-WebFlux-crud/src/main/java/com/example/webflux/WebfluxApplication.java ================================================ package com.example.webflux; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.data.mongodb.repository.config.EnableReactiveMongoRepositories; @SpringBootApplication @EnableReactiveMongoRepositories public class WebfluxApplication { public static void main(String[] args) { SpringApplication.run(WebfluxApplication.class, args); } } ================================================ FILE: 58.Spring-Boot-WebFlux-crud/src/main/java/com/example/webflux/controller/UserController.java ================================================ package com.example.webflux.controller; import com.example.webflux.domain.User; import com.example.webflux.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; /** * @author MrBird */ @RestController @RequestMapping("user") public class UserController { @Autowired private UserService userService; /** * 以数组的形式一次性返回所有数据 */ @GetMapping public Flux getUsers() { return userService.getUsers(); } /** * 以 Server sent events形式多次返回数据 */ @GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public Flux getUsersStream() { return userService.getUsers(); } @PostMapping public Mono createUser(User user) { return userService.createUser(user); } /** * 存在返回 200,不存在返回 404 */ @DeleteMapping("/{id}") public Mono> deleteUser(@PathVariable String id) { return userService.deleteUser(id) .then(Mono.just(new ResponseEntity(HttpStatus.OK))) .defaultIfEmpty(new ResponseEntity<>(HttpStatus.NOT_FOUND)); } /** * 存在返回修改后的 User * 不存在返回 404 */ @PutMapping("/{id}") public Mono> updateUser(@PathVariable String id, User user) { return userService.updateUser(id, user) .map(u -> new ResponseEntity<>(u, HttpStatus.OK)) .defaultIfEmpty(new ResponseEntity<>(HttpStatus.NOT_FOUND)); } /** * 根据用户 id查找 * 存在返回,不存在返回 404 */ @GetMapping("/{id}") public Mono> getUser(@PathVariable String id) { return userService.getUser(id) .map(user -> new ResponseEntity<>(user, HttpStatus.OK)) .defaultIfEmpty(new ResponseEntity<>(HttpStatus.NOT_FOUND)); } /** * 根据年龄段来查找 */ @GetMapping("/age/{from}/{to}") public Flux getUserByAge(@PathVariable Integer from, @PathVariable Integer to) { return userService.getUserByAge(from, to); } @GetMapping(value = "/stream/age/{from}/{to}", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public Flux getUserByAgeStream(@PathVariable Integer from, @PathVariable Integer to) { return userService.getUserByAge(from, to); } /** * 根据用户名查找 */ @GetMapping("/name/{name}") public Flux getUserByName(@PathVariable String name) { return userService.getUserByName(name); } @GetMapping(value = "/stream/name/{name}", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public Flux getUserByNameStream(@PathVariable String name) { return userService.getUserByName(name); } /** * 根据用户描述模糊查找 */ @GetMapping("/description/{description}") public Flux getUserByDescription(@PathVariable String description) { return userService.getUserByDescription(description); } @GetMapping(value = "/stream/description/{description}", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public Flux getUserByDescriptionStream(@PathVariable String description) { return userService.getUserByDescription(description); } /** * 根据多个检索条件查询 */ @GetMapping("/condition") public Flux getUserByCondition(int size, int page, User user) { return userService.getUserByCondition(size, page, user); } @GetMapping("/condition/count") public Mono getUserByConditionCount(User user) { return userService.getUserByConditionCount(user); } } ================================================ FILE: 58.Spring-Boot-WebFlux-crud/src/main/java/com/example/webflux/dao/UserDao.java ================================================ package com.example.webflux.dao; import com.example.webflux.domain.User; import org.springframework.data.mongodb.repository.ReactiveMongoRepository; import org.springframework.stereotype.Repository; import reactor.core.publisher.Flux; /** * @author MrBird */ @Repository public interface UserDao extends ReactiveMongoRepository { /** * 根据年龄段来查找 * * @param from from * @param to to * @return Flux */ Flux findByAgeBetween(Integer from, Integer to); /** * 更具描述来模糊查询用户 * * @param description 描述 * @return Flux */ Flux findByDescriptionIsLike(String description); /** * 通过用户名查询 * * @param name 用户名 * @return Flux */ Flux findByNameEquals(String name); } ================================================ FILE: 58.Spring-Boot-WebFlux-crud/src/main/java/com/example/webflux/domain/User.java ================================================ package com.example.webflux.domain; import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.mapping.Document; /** * @author MrBird */ @Document(collection = "user") public class User { @Id private String id; private String name; private Integer age; private String description; 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 Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } } ================================================ FILE: 58.Spring-Boot-WebFlux-crud/src/main/java/com/example/webflux/service/UserService.java ================================================ package com.example.webflux.service; import com.example.webflux.dao.UserDao; import com.example.webflux.domain.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.data.mongodb.core.ReactiveMongoTemplate; import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.Query; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; /** * @author MrBird */ @Service public class UserService { @Autowired private UserDao userDao; @Autowired private ReactiveMongoTemplate template; public Flux getUsers() { return userDao.findAll(); } public Mono getUser(String id) { return this.userDao.findById(id); } /** * 新增和修改都是 save方法, * id 存在为修改,id 不存在为新增 */ public Mono createUser(User user) { return userDao.save(user); } public Mono deleteUser(String id) { return this.userDao.findById(id) .flatMap(user -> this.userDao.delete(user)); } public Mono updateUser(String id, User user) { return this.userDao.findById(id) .flatMap(u -> { u.setName(user.getName()); u.setAge(user.getAge()); u.setDescription(user.getDescription()); return this.userDao.save(u); }); } public Flux getUserByAge(Integer from, Integer to) { return this.userDao.findByAgeBetween(from, to); } public Flux getUserByName(String name) { return this.userDao.findByNameEquals(name); } public Flux getUserByDescription(String description) { return this.userDao.findByDescriptionIsLike(description); } /** * 分页查询,只返回分页后的数据,count值需要通过 getUserByConditionCount * 方法获取 */ public Flux getUserByCondition(int size, int page, User user) { Query query = getQuery(user); Sort sort = new Sort(Sort.Direction.DESC, "age"); Pageable pageable = PageRequest.of(page, size, sort); return template.find(query.with(pageable), User.class); } /** * 返回 count,配合 getUserByCondition使用 */ public Mono getUserByConditionCount(User user) { Query query = getQuery(user); return template.count(query, User.class); } private Query getQuery(User user) { Query query = new Query(); Criteria criteria = new Criteria(); if (!StringUtils.isEmpty(user.getName())) { criteria.and("name").is(user.getName()); } if (!StringUtils.isEmpty(user.getDescription())) { criteria.and("description").regex(user.getDescription()); } query.addCriteria(criteria); return query; } } ================================================ FILE: 58.Spring-Boot-WebFlux-crud/src/main/resources/application.yml ================================================ spring: data: mongodb: host: localhost port: 27017 database: webflux ================================================ FILE: 58.Spring-Boot-WebFlux-crud/webflux crud.postman_collection.json ================================================ { "info": { "_postman_id": "8fa1e028-3088-4d19-bb08-4d41b3802487", "name": "webflux crud", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" }, "item": [ { "name": "createUser", "request": { "method": "POST", "header": [], "body": { "mode": "raw", "raw": "" }, "url": { "raw": "localhost:8080/user?name=mike&description=python developer&age=21", "host": [ "localhost" ], "port": "8080", "path": [ "user" ], "query": [ { "key": "name", "value": "mike" }, { "key": "description", "value": "python developer" }, { "key": "age", "value": "21" } ] } }, "response": [] }, { "name": "getUsers", "request": { "method": "GET", "header": [], "body": { "mode": "raw", "raw": "" }, "url": { "raw": "localhost:8080/user", "host": [ "localhost" ], "port": "8080", "path": [ "user" ] } }, "response": [] }, { "name": "getUser", "request": { "method": "GET", "header": [], "body": { "mode": "raw", "raw": "" }, "url": { "raw": "localhost:8080/user/5ca56280f08f0b6048fd470b", "host": [ "localhost" ], "port": "8080", "path": [ "user", "5ca56280f08f0b6048fd470b" ] } }, "response": [] }, { "name": "updateUser", "request": { "method": "PUT", "header": [], "body": { "mode": "raw", "raw": "" }, "url": { "raw": "localhost:8080/user/5ca40ee8f08f0b68cc06c001?id=5ca56280f08f0b6048fd470b&description=Java gosu&age=19", "host": [ "localhost" ], "port": "8080", "path": [ "user", "5ca40ee8f08f0b68cc06c001" ], "query": [ { "key": "id", "value": "5ca56280f08f0b6048fd470b" }, { "key": "description", "value": "Java gosu" }, { "key": "age", "value": "19" } ] } }, "response": [] }, { "name": "deleteUser", "request": { "method": "DELETE", "header": [], "body": { "mode": "raw", "raw": "" }, "url": { "raw": "localhost:8080/user/5ca56280f08f0b6048fd470b", "host": [ "localhost" ], "port": "8080", "path": [ "user", "5ca56280f08f0b6048fd470b" ] } }, "response": [] }, { "name": "getUsersStream", "request": { "method": "GET", "header": [], "body": { "mode": "raw", "raw": "" }, "url": { "raw": "localhost:8080/user/stream", "host": [ "localhost" ], "port": "8080", "path": [ "user", "stream" ] } }, "response": [] }, { "name": "getUserByAge", "request": { "method": "GET", "header": [], "body": { "mode": "raw", "raw": "" }, "url": { "raw": "localhost:8080/user/age/20/30", "host": [ "localhost" ], "port": "8080", "path": [ "user", "age", "20", "30" ] } }, "response": [] }, { "name": "getUserByName", "request": { "method": "GET", "header": [], "body": { "mode": "raw", "raw": "" }, "url": { "raw": "localhost:8080/user/name/mrbird", "host": [ "localhost" ], "port": "8080", "path": [ "user", "name", "mrbird" ] } }, "response": [] }, { "name": "getUserByDescription", "request": { "method": "GET", "header": [], "body": { "mode": "raw", "raw": "" }, "url": { "raw": "localhost:8080/user/description/ui", "host": [ "localhost" ], "port": "8080", "path": [ "user", "description", "ui" ] } }, "response": [] }, { "name": "getUserByCondition", "request": { "method": "GET", "header": [], "body": { "mode": "raw", "raw": "" }, "url": { "raw": "localhost:8080/user/condition?size=2&page=0", "host": [ "localhost" ], "port": "8080", "path": [ "user", "condition" ], "query": [ { "key": "name", "value": "mrbird", "disabled": true }, { "key": "description", "value": "r", "disabled": true }, { "key": "size", "value": "2" }, { "key": "page", "value": "0" } ] } }, "response": [] } ] } ================================================ FILE: 59.Spring-Security-SessionManager/pom.xml ================================================ 4.0.0 cc.mrbird Security 1.0-SNAPSHOT jar Security Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.14.RELEASE UTF-8 UTF-8 1.8 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-security org.springframework.social spring-social-config org.apache.commons commons-lang3 3.7 org.springframework.session spring-session org.springframework.boot spring-boot-starter-data-redis org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 59.Spring-Security-SessionManager/src/main/java/cc/mrbird/SecurityApplication.java ================================================ package cc.mrbird; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class SecurityApplication { public static void main(String[] args) { SpringApplication.run(SecurityApplication.class, args); } } ================================================ FILE: 59.Spring-Security-SessionManager/src/main/java/cc/mrbird/domain/MyUser.java ================================================ package cc.mrbird.domain; import java.io.Serializable; public class MyUser implements Serializable { private static final long serialVersionUID = 3497935890426858541L; private String userName; private String password; private boolean accountNonExpired = true; private boolean accountNonLocked= true; private boolean credentialsNonExpired= true; private boolean enabled= true; public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public boolean isAccountNonExpired() { return accountNonExpired; } public void setAccountNonExpired(boolean accountNonExpired) { this.accountNonExpired = accountNonExpired; } public boolean isAccountNonLocked() { return accountNonLocked; } public void setAccountNonLocked(boolean accountNonLocked) { this.accountNonLocked = accountNonLocked; } public boolean isCredentialsNonExpired() { return credentialsNonExpired; } public void setCredentialsNonExpired(boolean credentialsNonExpired) { this.credentialsNonExpired = credentialsNonExpired; } public boolean isEnabled() { return enabled; } public void setEnabled(boolean enabled) { this.enabled = enabled; } } ================================================ FILE: 59.Spring-Security-SessionManager/src/main/java/cc/mrbird/handler/MyAuthenticationFailureHandler.java ================================================ package cc.mrbird.handler; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.stereotype.Component; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @Component public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler { @Autowired private ObjectMapper mapper; @Override public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException { response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value()); response.setContentType("application/json;charset=utf-8"); response.getWriter().write(mapper.writeValueAsString(exception.getMessage())); } } ================================================ FILE: 59.Spring-Security-SessionManager/src/main/java/cc/mrbird/handler/MyAuthenticationSucessHandler.java ================================================ package cc.mrbird.handler; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.Authentication; import org.springframework.security.web.DefaultRedirectStrategy; import org.springframework.security.web.RedirectStrategy; import org.springframework.security.web.authentication.AuthenticationSuccessHandler; import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; import org.springframework.security.web.savedrequest.HttpSessionRequestCache; import org.springframework.security.web.savedrequest.RequestCache; import org.springframework.security.web.savedrequest.SavedRequest; import org.springframework.stereotype.Component; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @Component public class MyAuthenticationSucessHandler implements AuthenticationSuccessHandler { // private RequestCache requestCache = new HttpSessionRequestCache(); private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy(); // // @Autowired // private ObjectMapper mapper; @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException { // response.setContentType("application/json;charset=utf-8"); // response.getWriter().write(mapper.writeValueAsString(authentication)); // SavedRequest savedRequest = requestCache.getRequest(request, response); // System.out.println(savedRequest.getRedirectUrl()); // redirectStrategy.sendRedirect(request, response, savedRequest.getRedirectUrl()); redirectStrategy.sendRedirect(request, response, "/index"); } } ================================================ FILE: 59.Spring-Security-SessionManager/src/main/java/cc/mrbird/security/browser/BrowserSecurityConfig.java ================================================ package cc.mrbird.security.browser; import cc.mrbird.handler.MyAuthenticationFailureHandler; import cc.mrbird.handler.MyAuthenticationSucessHandler; import cc.mrbird.session.MySessionExpiredStrategy; import cc.mrbird.validate.code.ValidateCodeFilter; import cc.mrbird.validate.smscode.SmsAuthenticationConfig; import cc.mrbird.validate.smscode.SmsCodeFilter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; @Configuration public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private MyAuthenticationSucessHandler authenticationSucessHandler; @Autowired private MyAuthenticationFailureHandler authenticationFailureHandler; @Autowired private ValidateCodeFilter validateCodeFilter; @Autowired private SmsCodeFilter smsCodeFilter; @Autowired private SmsAuthenticationConfig smsAuthenticationConfig; @Autowired private MySessionExpiredStrategy sessionExpiredStrategy; @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Override protected void configure(HttpSecurity http) throws Exception { http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class) // 添加验证码校验过滤器 .addFilterBefore(smsCodeFilter,UsernamePasswordAuthenticationFilter.class) // 添加短信验证码校验过滤器 .formLogin() // 表单登录 // http.httpBasic() // HTTP Basic .loginPage("/authentication/require") // 登录跳转 URL .loginProcessingUrl("/login") // 处理表单登录 URL .successHandler(authenticationSucessHandler) // 处理登录成功 .failureHandler(authenticationFailureHandler) // 处理登录失败 .and() .authorizeRequests() // 授权配置 .antMatchers("/authentication/require", "/login.html", "/code/image","/code/sms","/session/invalid").permitAll() // 无需认证的请求路径 .anyRequest() // 所有请求 .authenticated() // 都需要认证 .and() .sessionManagement() // 添加 Session管理器 .invalidSessionUrl("/session/invalid") // Session失效后跳转到这个链接 .maximumSessions(1) .maxSessionsPreventsLogin(true) .expiredSessionStrategy(sessionExpiredStrategy) .and() .and() .csrf().disable() .apply(smsAuthenticationConfig); // 将短信验证码认证配置加到 Spring Security 中 } } ================================================ FILE: 59.Spring-Security-SessionManager/src/main/java/cc/mrbird/security/browser/UserDetailService.java ================================================ package cc.mrbird.security.browser; import cc.mrbird.domain.MyUser; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.crypto.password.PasswordEncoder; @Configuration public class UserDetailService implements UserDetailsService { @Autowired private PasswordEncoder passwordEncoder; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { // 模拟一个用户,替代数据库获取逻辑 MyUser user = new MyUser(); user.setUserName(username); user.setPassword(this.passwordEncoder.encode("123456")); // 输出加密后的密码 System.out.println(user.getPassword()); return new User(username, user.getPassword(), user.isEnabled(), user.isAccountNonExpired(), user.isCredentialsNonExpired(), user.isAccountNonLocked(), AuthorityUtils.commaSeparatedStringToAuthorityList("admin")); } } ================================================ FILE: 59.Spring-Security-SessionManager/src/main/java/cc/mrbird/session/MySessionExpiredStrategy.java ================================================ package cc.mrbird.session; import org.springframework.http.HttpStatus; import org.springframework.security.web.session.SessionInformationExpiredEvent; import org.springframework.security.web.session.SessionInformationExpiredStrategy; import org.springframework.stereotype.Component; import javax.servlet.ServletException; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @author MrBird */ @Component public class MySessionExpiredStrategy implements SessionInformationExpiredStrategy { @Override public void onExpiredSessionDetected(SessionInformationExpiredEvent event) throws IOException, ServletException { HttpServletResponse response = event.getResponse(); response.setStatus(HttpStatus.UNAUTHORIZED.value()); response.setContentType("application/json;charset=utf-8"); response.getWriter().write("您的账号已经在别的地方登录,当前登录已失效。如果密码遭到泄露,请立即修改密码!"); } } ================================================ FILE: 59.Spring-Security-SessionManager/src/main/java/cc/mrbird/validate/code/ImageCode.java ================================================ package cc.mrbird.validate.code; import java.awt.image.BufferedImage; import java.io.Serializable; import java.time.LocalDateTime; public class ImageCode implements Serializable { private static final long serialVersionUID = -7831615057416168810L; private BufferedImage image; private String code; private LocalDateTime expireTime; public ImageCode(BufferedImage image, String code, int expireIn) { this.image = image; this.code = code; this.expireTime = LocalDateTime.now().plusSeconds(expireIn); } public ImageCode(BufferedImage image, String code, LocalDateTime expireTime) { this.image = image; this.code = code; this.expireTime = expireTime; } boolean isExpire() { return LocalDateTime.now().isAfter(expireTime); } public BufferedImage getImage() { return image; } public void setImage(BufferedImage image) { this.image = image; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } public LocalDateTime getExpireTime() { return expireTime; } public void setExpireTime(LocalDateTime expireTime) { this.expireTime = expireTime; } } ================================================ FILE: 59.Spring-Security-SessionManager/src/main/java/cc/mrbird/validate/code/ValidateCodeException.java ================================================ package cc.mrbird.validate.code; import org.springframework.security.core.AuthenticationException; public class ValidateCodeException extends AuthenticationException { private static final long serialVersionUID = 5022575393500654458L; public ValidateCodeException(String message) { super(message); } } ================================================ FILE: 59.Spring-Security-SessionManager/src/main/java/cc/mrbird/validate/code/ValidateCodeFilter.java ================================================ package cc.mrbird.validate.code; import cc.mrbird.web.controller.ValidateController; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.social.connect.web.HttpSessionSessionStrategy; import org.springframework.social.connect.web.SessionStrategy; import org.springframework.stereotype.Component; import org.springframework.web.bind.ServletRequestBindingException; import org.springframework.web.bind.ServletRequestUtils; import org.springframework.web.context.request.ServletWebRequest; import org.springframework.web.filter.OncePerRequestFilter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @Component public class ValidateCodeFilter extends OncePerRequestFilter { @Autowired private AuthenticationFailureHandler authenticationFailureHandler; private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy(); @Override protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException { if (StringUtils.equalsIgnoreCase("/login", httpServletRequest.getRequestURI()) && StringUtils.equalsIgnoreCase(httpServletRequest.getMethod(), "post")) { try { validateCode(new ServletWebRequest(httpServletRequest)); } catch (ValidateCodeException e) { authenticationFailureHandler.onAuthenticationFailure(httpServletRequest, httpServletResponse, e); return; } } filterChain.doFilter(httpServletRequest, httpServletResponse); } private void validateCode(ServletWebRequest servletWebRequest) throws ServletRequestBindingException { ImageCode codeInSession = (ImageCode) sessionStrategy.getAttribute(servletWebRequest, ValidateController.SESSION_KEY_IMAGE_CODE); String codeInRequest = ServletRequestUtils.getStringParameter(servletWebRequest.getRequest(), "imageCode"); if (StringUtils.isBlank(codeInRequest)) { throw new ValidateCodeException("验证码不能为空!"); } if (codeInSession == null) { throw new ValidateCodeException("验证码不存在!"); } if (codeInSession.isExpire()) { sessionStrategy.removeAttribute(servletWebRequest, ValidateController.SESSION_KEY_IMAGE_CODE); throw new ValidateCodeException("验证码已过期!"); } if (!StringUtils.equalsIgnoreCase(codeInSession.getCode(), codeInRequest)) { throw new ValidateCodeException("验证码不正确!"); } sessionStrategy.removeAttribute(servletWebRequest, ValidateController.SESSION_KEY_IMAGE_CODE); } } ================================================ FILE: 59.Spring-Security-SessionManager/src/main/java/cc/mrbird/validate/smscode/SmsAuthenticationConfig.java ================================================ package cc.mrbird.validate.smscode; import cc.mrbird.security.browser.UserDetailService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.SecurityConfigurerAdapter; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.web.DefaultSecurityFilterChain; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.security.web.authentication.AuthenticationSuccessHandler; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.stereotype.Component; @Component public class SmsAuthenticationConfig extends SecurityConfigurerAdapter { @Autowired private AuthenticationSuccessHandler authenticationSuccessHandler; @Autowired private AuthenticationFailureHandler authenticationFailureHandler; @Autowired private UserDetailService userDetailService; @Override public void configure(HttpSecurity http) throws Exception { SmsAuthenticationFilter smsAuthenticationFilter = new SmsAuthenticationFilter(); smsAuthenticationFilter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class)); smsAuthenticationFilter.setAuthenticationSuccessHandler(authenticationSuccessHandler); smsAuthenticationFilter.setAuthenticationFailureHandler(authenticationFailureHandler); SmsAuthenticationProvider smsAuthenticationProvider = new SmsAuthenticationProvider(); smsAuthenticationProvider.setUserDetailService(userDetailService); http.authenticationProvider(smsAuthenticationProvider) .addFilterAfter(smsAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); } } ================================================ FILE: 59.Spring-Security-SessionManager/src/main/java/cc/mrbird/validate/smscode/SmsAuthenticationFilter.java ================================================ package cc.mrbird.validate.smscode; import org.springframework.security.authentication.AuthenticationServiceException; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.util.Assert; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class SmsAuthenticationFilter extends AbstractAuthenticationProcessingFilter { public static final String MOBILE_KEY = "mobile"; private String mobileParameter = MOBILE_KEY; private boolean postOnly = true; public SmsAuthenticationFilter() { super(new AntPathRequestMatcher("/login/mobile", "POST")); } public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { if (postOnly && !request.getMethod().equals("POST")) { throw new AuthenticationServiceException( "Authentication method not supported: " + request.getMethod()); } String mobile = obtainMobile(request); if (mobile == null) { mobile = ""; } mobile = mobile.trim(); SmsAuthenticationToken authRequest = new SmsAuthenticationToken(mobile); setDetails(request, authRequest); return this.getAuthenticationManager().authenticate(authRequest); } protected String obtainMobile(HttpServletRequest request) { return request.getParameter(mobileParameter); } protected void setDetails(HttpServletRequest request, SmsAuthenticationToken authRequest) { authRequest.setDetails(authenticationDetailsSource.buildDetails(request)); } public void setMobileParameter(String mobileParameter) { Assert.hasText(mobileParameter, "mobile parameter must not be empty or null"); this.mobileParameter = mobileParameter; } public void setPostOnly(boolean postOnly) { this.postOnly = postOnly; } public final String getMobileParameter() { return mobileParameter; } } ================================================ FILE: 59.Spring-Security-SessionManager/src/main/java/cc/mrbird/validate/smscode/SmsAuthenticationProvider.java ================================================ package cc.mrbird.validate.smscode; import cc.mrbird.security.browser.UserDetailService; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.InternalAuthenticationServiceException; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.userdetails.UserDetails; public class SmsAuthenticationProvider implements AuthenticationProvider { private UserDetailService userDetailService; @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { SmsAuthenticationToken authenticationToken = (SmsAuthenticationToken) authentication; UserDetails userDetails = userDetailService.loadUserByUsername((String) authenticationToken.getPrincipal()); if (userDetails == null) throw new InternalAuthenticationServiceException("未找到与该手机号对应的用户"); SmsAuthenticationToken authenticationResult = new SmsAuthenticationToken(userDetails, userDetails.getAuthorities()); authenticationResult.setDetails(authenticationToken.getDetails()); return authenticationResult; } @Override public boolean supports(Class aClass) { return SmsAuthenticationToken.class.isAssignableFrom(aClass); } public UserDetailService getUserDetailService() { return userDetailService; } public void setUserDetailService(UserDetailService userDetailService) { this.userDetailService = userDetailService; } } ================================================ FILE: 59.Spring-Security-SessionManager/src/main/java/cc/mrbird/validate/smscode/SmsAuthenticationToken.java ================================================ package cc.mrbird.validate.smscode; import org.springframework.security.authentication.AbstractAuthenticationToken; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.SpringSecurityCoreVersion; import java.util.Collection; public class SmsAuthenticationToken extends AbstractAuthenticationToken { private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID; private final Object principal; public SmsAuthenticationToken(String mobile) { super(null); this.principal = mobile; setAuthenticated(false); } public SmsAuthenticationToken(Object principal, Collection authorities) { super(authorities); this.principal = principal; super.setAuthenticated(true); // must use super, as we override } @Override public Object getCredentials() { return null; } public Object getPrincipal() { return this.principal; } public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException { if (isAuthenticated) { throw new IllegalArgumentException( "Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead"); } super.setAuthenticated(false); } @Override public void eraseCredentials() { super.eraseCredentials(); } } ================================================ FILE: 59.Spring-Security-SessionManager/src/main/java/cc/mrbird/validate/smscode/SmsCode.java ================================================ package cc.mrbird.validate.smscode; import java.time.LocalDateTime; public class SmsCode { private String code; private LocalDateTime expireTime; public SmsCode(String code, int expireIn) { this.code = code; this.expireTime = LocalDateTime.now().plusSeconds(expireIn); } public SmsCode(String code, LocalDateTime expireTime) { this.code = code; this.expireTime = expireTime; } boolean isExpire() { return LocalDateTime.now().isAfter(expireTime); } public String getCode() { return code; } public void setCode(String code) { this.code = code; } public LocalDateTime getExpireTime() { return expireTime; } public void setExpireTime(LocalDateTime expireTime) { this.expireTime = expireTime; } } ================================================ FILE: 59.Spring-Security-SessionManager/src/main/java/cc/mrbird/validate/smscode/SmsCodeFilter.java ================================================ package cc.mrbird.validate.smscode; import cc.mrbird.validate.code.ValidateCodeException; import cc.mrbird.web.controller.ValidateController; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.social.connect.web.HttpSessionSessionStrategy; import org.springframework.social.connect.web.SessionStrategy; import org.springframework.stereotype.Component; import org.springframework.web.bind.ServletRequestBindingException; import org.springframework.web.bind.ServletRequestUtils; import org.springframework.web.context.request.ServletWebRequest; import org.springframework.web.filter.OncePerRequestFilter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @Component public class SmsCodeFilter extends OncePerRequestFilter { @Autowired private AuthenticationFailureHandler authenticationFailureHandler; private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy(); @Override protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException { if (StringUtils.equalsIgnoreCase("/login/mobile", httpServletRequest.getRequestURI()) && StringUtils.equalsIgnoreCase(httpServletRequest.getMethod(), "post")) { try { validateCode(new ServletWebRequest(httpServletRequest)); } catch (ValidateCodeException e) { authenticationFailureHandler.onAuthenticationFailure(httpServletRequest, httpServletResponse, e); return; } } filterChain.doFilter(httpServletRequest, httpServletResponse); } private void validateCode(ServletWebRequest servletWebRequest) throws ServletRequestBindingException { String smsCodeInRequest = ServletRequestUtils.getStringParameter(servletWebRequest.getRequest(), "smsCode"); String mobileInRequest = ServletRequestUtils.getStringParameter(servletWebRequest.getRequest(), "smsCode"); SmsCode codeInSession = (SmsCode) sessionStrategy.getAttribute(servletWebRequest, ValidateController.SESSION_KEY_SMS_CODE + mobileInRequest); if (StringUtils.isBlank(smsCodeInRequest)) { throw new ValidateCodeException("验证码不能为空!"); } if (codeInSession == null) { throw new ValidateCodeException("验证码不存在!"); } if (codeInSession.isExpire()) { sessionStrategy.removeAttribute(servletWebRequest, ValidateController.SESSION_KEY_IMAGE_CODE); throw new ValidateCodeException("验证码已过期!"); } if (!StringUtils.equalsIgnoreCase(codeInSession.getCode(), smsCodeInRequest)) { throw new ValidateCodeException("验证码不正确!"); } sessionStrategy.removeAttribute(servletWebRequest, ValidateController.SESSION_KEY_IMAGE_CODE); } } ================================================ FILE: 59.Spring-Security-SessionManager/src/main/java/cc/mrbird/web/controller/BrowserSecurityController.java ================================================ package cc.mrbird.web.controller; import org.springframework.http.HttpStatus; import org.springframework.security.web.DefaultRedirectStrategy; import org.springframework.security.web.RedirectStrategy; import org.springframework.security.web.savedrequest.HttpSessionRequestCache; import org.springframework.security.web.savedrequest.RequestCache; import org.springframework.security.web.savedrequest.SavedRequest; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @author MrBird */ @RestController public class BrowserSecurityController { private RequestCache requestCache = new HttpSessionRequestCache(); private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy(); @GetMapping("/authentication/require") @ResponseStatus(HttpStatus.UNAUTHORIZED) public String requireAuthentication(HttpServletRequest request, HttpServletResponse response) throws IOException { SavedRequest savedRequest = requestCache.getRequest(request, response); if (savedRequest != null) { String targetUrl = savedRequest.getRedirectUrl(); if (StringUtils.endsWithIgnoreCase(targetUrl, ".html")) redirectStrategy.sendRedirect(request, response, "/login.html"); } return "访问的资源需要身份认证!"; } @GetMapping("/session/invalid") @ResponseStatus(HttpStatus.UNAUTHORIZED) public String sessionInvalid(){ return "session已失效,请重新认证"; } } ================================================ FILE: 59.Spring-Security-SessionManager/src/main/java/cc/mrbird/web/controller/TestController.java ================================================ package cc.mrbird.web.controller; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class TestController { @GetMapping("hello") public String hello() { return "hello spring security"; } @GetMapping("index") public Object index(Authentication authentication) { // return SecurityContextHolder.getContext().getAuthentication(); return authentication; } } ================================================ FILE: 59.Spring-Security-SessionManager/src/main/java/cc/mrbird/web/controller/ValidateController.java ================================================ package cc.mrbird.web.controller; import cc.mrbird.validate.code.ImageCode; import cc.mrbird.validate.smscode.SmsCode; import org.apache.commons.lang3.RandomStringUtils; import org.springframework.social.connect.web.HttpSessionSessionStrategy; import org.springframework.social.connect.web.SessionStrategy; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.context.request.ServletWebRequest; import javax.imageio.ImageIO; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.awt.*; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.Random; @RestController public class ValidateController { public final static String SESSION_KEY_IMAGE_CODE = "SESSION_KEY_IMAGE_CODE"; public final static String SESSION_KEY_SMS_CODE = "SESSION_KEY_SMS_CODE"; private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy(); @GetMapping("/code/image") public void createCode(HttpServletRequest request, HttpServletResponse response) throws IOException { ImageCode imageCode = createImageCode(); ImageCode codeInRedis = new ImageCode(null,imageCode.getCode(),imageCode.getExpireTime()); sessionStrategy.setAttribute(new ServletWebRequest(request), SESSION_KEY_IMAGE_CODE, codeInRedis); ImageIO.write(imageCode.getImage(), "jpeg", response.getOutputStream()); } @GetMapping("/code/sms") public void createSmsCode(HttpServletRequest request, HttpServletResponse response, String mobile) { SmsCode smsCode = createSMSCode(); sessionStrategy.setAttribute(new ServletWebRequest(request), SESSION_KEY_SMS_CODE + mobile, smsCode); // 输出验证码到控制台代替短信发送服务 System.out.println("您的登录验证码为:" + smsCode.getCode() + ",有效时间为60秒"); } private SmsCode createSMSCode() { String code = RandomStringUtils.randomNumeric(6); return new SmsCode(code, 60); } private ImageCode createImageCode() { int width = 100; // 验证码图片宽度 int height = 36; // 验证码图片长度 int length = 4; // 验证码位数 int expireIn = 60; // 验证码有效时间 60s BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); Graphics g = image.getGraphics(); Random random = new Random(); g.setColor(getRandColor(200, 250)); g.fillRect(0, 0, width, height); g.setFont(new Font("Times New Roman", Font.ITALIC, 20)); g.setColor(getRandColor(160, 200)); for (int i = 0; i < 155; i++) { int x = random.nextInt(width); int y = random.nextInt(height); int xl = random.nextInt(12); int yl = random.nextInt(12); g.drawLine(x, y, x + xl, y + yl); } StringBuilder sRand = new StringBuilder(); for (int i = 0; i < length; i++) { String rand = String.valueOf(random.nextInt(10)); sRand.append(rand); g.setColor(new Color(20 + random.nextInt(110), 20 + random.nextInt(110), 20 + random.nextInt(110))); g.drawString(rand, 13 * i + 6, 16); } g.dispose(); return new ImageCode(image, sRand.toString(), expireIn); } private Color getRandColor(int fc, int bc) { Random random = new Random(); 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); } } ================================================ FILE: 59.Spring-Security-SessionManager/src/main/resources/application.yml ================================================ security: basic: enabled: true server: session: timeout: 3600 spring: session: store-type: redis ================================================ FILE: 59.Spring-Security-SessionManager/src/main/resources/resources/css/login.css ================================================ .login-page { width: 360px; padding: 8% 0 0; margin: auto; } .form { position: relative; z-index: 1; background: #ffffff; max-width: 360px; margin: 0 auto 100px; padding: 45px; text-align: center; box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.2), 0 5px 5px 0 rgba(0, 0, 0, 0.24); } .form input { outline: 0; background: #f2f2f2; width: 100%; border: 0; margin: 0 0 15px; padding: 15px; box-sizing: border-box; font-size: 14px; } .form button { text-transform: uppercase; outline: 0; background: #4caf50; width: 100%; border: 0; padding: 15px; color: #ffffff; font-size: 14px; -webkit-transition: all 0.3 ease; transition: all 0.3 ease; cursor: pointer; } .form button:hover, .form button:active, .form button:focus { background: #43a047; } .form .message { margin: 15px 0 0; color: #b3b3b3; font-size: 12px; } .form .message a { color: #4caf50; text-decoration: none; } .form .register-form { display: none; } .container { position: relative; z-index: 1; max-width: 300px; margin: 0 auto; } .container:before, .container:after { content: ""; display: block; clear: both; } .container .info { margin: 50px auto; text-align: center; } .container .info h1 { margin: 0 0 15px; padding: 0; font-size: 36px; font-weight: 300; color: #1a1a1a; } .container .info span { color: #4d4d4d; font-size: 12px; } .container .info span a { color: #000000; text-decoration: none; } .container .info span .fa { color: #ef3b3a; } body { background: #76b852; /* fallback for old browsers */ background: -webkit-linear-gradient(right, #76b852, #8dc26f); background: -moz-linear-gradient(right, #76b852, #8dc26f); background: -o-linear-gradient(right, #76b852, #8dc26f); background: linear-gradient(to left, #76b852, #8dc26f); font-family: Lato,"PingFang SC","Microsoft YaHei",sans-serif; } ================================================ FILE: 59.Spring-Security-SessionManager/src/main/resources/resources/login.html ================================================ 登录 ================================================ FILE: 60.Spring-Security-Logout/pom.xml ================================================ 4.0.0 cc.mrbird Security 1.0-SNAPSHOT jar Security Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.14.RELEASE UTF-8 UTF-8 1.8 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-security org.springframework.social spring-social-config org.apache.commons commons-lang3 3.7 org.springframework.session spring-session org.springframework.boot spring-boot-starter-data-redis org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 60.Spring-Security-Logout/src/main/java/cc/mrbird/SecurityApplication.java ================================================ package cc.mrbird; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class SecurityApplication { public static void main(String[] args) { SpringApplication.run(SecurityApplication.class, args); } } ================================================ FILE: 60.Spring-Security-Logout/src/main/java/cc/mrbird/domain/MyUser.java ================================================ package cc.mrbird.domain; import java.io.Serializable; public class MyUser implements Serializable { private static final long serialVersionUID = 3497935890426858541L; private String userName; private String password; private boolean accountNonExpired = true; private boolean accountNonLocked= true; private boolean credentialsNonExpired= true; private boolean enabled= true; public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public boolean isAccountNonExpired() { return accountNonExpired; } public void setAccountNonExpired(boolean accountNonExpired) { this.accountNonExpired = accountNonExpired; } public boolean isAccountNonLocked() { return accountNonLocked; } public void setAccountNonLocked(boolean accountNonLocked) { this.accountNonLocked = accountNonLocked; } public boolean isCredentialsNonExpired() { return credentialsNonExpired; } public void setCredentialsNonExpired(boolean credentialsNonExpired) { this.credentialsNonExpired = credentialsNonExpired; } public boolean isEnabled() { return enabled; } public void setEnabled(boolean enabled) { this.enabled = enabled; } } ================================================ FILE: 60.Spring-Security-Logout/src/main/java/cc/mrbird/handler/MyAuthenticationFailureHandler.java ================================================ package cc.mrbird.handler; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.stereotype.Component; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @Component public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler { @Autowired private ObjectMapper mapper; @Override public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException { response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value()); response.setContentType("application/json;charset=utf-8"); response.getWriter().write(mapper.writeValueAsString(exception.getMessage())); } } ================================================ FILE: 60.Spring-Security-Logout/src/main/java/cc/mrbird/handler/MyAuthenticationSucessHandler.java ================================================ package cc.mrbird.handler; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.Authentication; import org.springframework.security.web.DefaultRedirectStrategy; import org.springframework.security.web.RedirectStrategy; import org.springframework.security.web.authentication.AuthenticationSuccessHandler; import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; import org.springframework.security.web.savedrequest.HttpSessionRequestCache; import org.springframework.security.web.savedrequest.RequestCache; import org.springframework.security.web.savedrequest.SavedRequest; import org.springframework.stereotype.Component; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @Component public class MyAuthenticationSucessHandler implements AuthenticationSuccessHandler { // private RequestCache requestCache = new HttpSessionRequestCache(); private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy(); // // @Autowired // private ObjectMapper mapper; @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException { // response.setContentType("application/json;charset=utf-8"); // response.getWriter().write(mapper.writeValueAsString(authentication)); // SavedRequest savedRequest = requestCache.getRequest(request, response); // System.out.println(savedRequest.getRedirectUrl()); // redirectStrategy.sendRedirect(request, response, savedRequest.getRedirectUrl()); redirectStrategy.sendRedirect(request, response, "/index"); } } ================================================ FILE: 60.Spring-Security-Logout/src/main/java/cc/mrbird/handler/MyLogOutSuccessHandler.java ================================================ package cc.mrbird.handler; import org.springframework.http.HttpStatus; import org.springframework.security.core.Authentication; import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; import org.springframework.stereotype.Component; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @author MrBird */ @Component public class MyLogOutSuccessHandler implements LogoutSuccessHandler { @Override public void onLogoutSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException { httpServletResponse.setStatus(HttpStatus.UNAUTHORIZED.value()); httpServletResponse.setContentType("application/json;charset=utf-8"); httpServletResponse.getWriter().write("退出成功,请重新登录"); } } ================================================ FILE: 60.Spring-Security-Logout/src/main/java/cc/mrbird/security/browser/BrowserSecurityConfig.java ================================================ package cc.mrbird.security.browser; import cc.mrbird.handler.MyAuthenticationFailureHandler; import cc.mrbird.handler.MyAuthenticationSucessHandler; import cc.mrbird.handler.MyLogOutSuccessHandler; import cc.mrbird.session.MySessionExpiredStrategy; import cc.mrbird.validate.code.ValidateCodeFilter; import cc.mrbird.validate.smscode.SmsAuthenticationConfig; import cc.mrbird.validate.smscode.SmsCodeFilter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; @Configuration public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private MyAuthenticationSucessHandler authenticationSucessHandler; @Autowired private MyAuthenticationFailureHandler authenticationFailureHandler; @Autowired private ValidateCodeFilter validateCodeFilter; @Autowired private SmsCodeFilter smsCodeFilter; @Autowired private SmsAuthenticationConfig smsAuthenticationConfig; @Autowired private MySessionExpiredStrategy sessionExpiredStrategy; @Autowired private MyLogOutSuccessHandler logOutSuccessHandler; @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Override protected void configure(HttpSecurity http) throws Exception { http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class) // 添加验证码校验过滤器 .addFilterBefore(smsCodeFilter,UsernamePasswordAuthenticationFilter.class) // 添加短信验证码校验过滤器 .formLogin() // 表单登录 // http.httpBasic() // HTTP Basic .loginPage("/authentication/require") // 登录跳转 URL .loginProcessingUrl("/login") // 处理表单登录 URL .successHandler(authenticationSucessHandler) // 处理登录成功 .failureHandler(authenticationFailureHandler) // 处理登录失败 .and() .authorizeRequests() // 授权配置 .antMatchers("/authentication/require", "/login.html", "/code/image","/code/sms","/session/invalid", "/signout/success").permitAll() // 无需认证的请求路径 .anyRequest() // 所有请求 .authenticated() // 都需要认证 .and() .sessionManagement() // 添加 Session管理器 .invalidSessionUrl("/session/invalid") // Session失效后跳转到这个链接 .maximumSessions(1) .maxSessionsPreventsLogin(true) .expiredSessionStrategy(sessionExpiredStrategy) .and() .and() .logout() .logoutUrl("/signout") // .logoutSuccessUrl("/signout/success") .logoutSuccessHandler(logOutSuccessHandler) .deleteCookies("JSESSIONID") .and() .csrf().disable() .apply(smsAuthenticationConfig); // 将短信验证码认证配置加到 Spring Security 中 } } ================================================ FILE: 60.Spring-Security-Logout/src/main/java/cc/mrbird/security/browser/UserDetailService.java ================================================ package cc.mrbird.security.browser; import cc.mrbird.domain.MyUser; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.crypto.password.PasswordEncoder; @Configuration public class UserDetailService implements UserDetailsService { @Autowired private PasswordEncoder passwordEncoder; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { // 模拟一个用户,替代数据库获取逻辑 MyUser user = new MyUser(); user.setUserName(username); user.setPassword(this.passwordEncoder.encode("123456")); // 输出加密后的密码 System.out.println(user.getPassword()); return new User(username, user.getPassword(), user.isEnabled(), user.isAccountNonExpired(), user.isCredentialsNonExpired(), user.isAccountNonLocked(), AuthorityUtils.commaSeparatedStringToAuthorityList("admin")); } } ================================================ FILE: 60.Spring-Security-Logout/src/main/java/cc/mrbird/session/MySessionExpiredStrategy.java ================================================ package cc.mrbird.session; import org.springframework.http.HttpStatus; import org.springframework.security.web.session.SessionInformationExpiredEvent; import org.springframework.security.web.session.SessionInformationExpiredStrategy; import org.springframework.stereotype.Component; import javax.servlet.ServletException; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @author MrBird */ @Component public class MySessionExpiredStrategy implements SessionInformationExpiredStrategy { @Override public void onExpiredSessionDetected(SessionInformationExpiredEvent event) throws IOException, ServletException { HttpServletResponse response = event.getResponse(); response.setStatus(HttpStatus.UNAUTHORIZED.value()); response.setContentType("application/json;charset=utf-8"); response.getWriter().write("您的账号已经在别的地方登录,当前登录已失效。如果密码遭到泄露,请立即修改密码!"); } } ================================================ FILE: 60.Spring-Security-Logout/src/main/java/cc/mrbird/validate/code/ImageCode.java ================================================ package cc.mrbird.validate.code; import java.awt.image.BufferedImage; import java.io.Serializable; import java.time.LocalDateTime; public class ImageCode implements Serializable { private static final long serialVersionUID = -7831615057416168810L; private BufferedImage image; private String code; private LocalDateTime expireTime; public ImageCode(BufferedImage image, String code, int expireIn) { this.image = image; this.code = code; this.expireTime = LocalDateTime.now().plusSeconds(expireIn); } public ImageCode(BufferedImage image, String code, LocalDateTime expireTime) { this.image = image; this.code = code; this.expireTime = expireTime; } boolean isExpire() { return LocalDateTime.now().isAfter(expireTime); } public BufferedImage getImage() { return image; } public void setImage(BufferedImage image) { this.image = image; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } public LocalDateTime getExpireTime() { return expireTime; } public void setExpireTime(LocalDateTime expireTime) { this.expireTime = expireTime; } } ================================================ FILE: 60.Spring-Security-Logout/src/main/java/cc/mrbird/validate/code/ValidateCodeException.java ================================================ package cc.mrbird.validate.code; import org.springframework.security.core.AuthenticationException; public class ValidateCodeException extends AuthenticationException { private static final long serialVersionUID = 5022575393500654458L; public ValidateCodeException(String message) { super(message); } } ================================================ FILE: 60.Spring-Security-Logout/src/main/java/cc/mrbird/validate/code/ValidateCodeFilter.java ================================================ package cc.mrbird.validate.code; import cc.mrbird.web.controller.ValidateController; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.social.connect.web.HttpSessionSessionStrategy; import org.springframework.social.connect.web.SessionStrategy; import org.springframework.stereotype.Component; import org.springframework.web.bind.ServletRequestBindingException; import org.springframework.web.bind.ServletRequestUtils; import org.springframework.web.context.request.ServletWebRequest; import org.springframework.web.filter.OncePerRequestFilter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @Component public class ValidateCodeFilter extends OncePerRequestFilter { @Autowired private AuthenticationFailureHandler authenticationFailureHandler; private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy(); @Override protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException { if (StringUtils.equalsIgnoreCase("/login", httpServletRequest.getRequestURI()) && StringUtils.equalsIgnoreCase(httpServletRequest.getMethod(), "post")) { try { validateCode(new ServletWebRequest(httpServletRequest)); } catch (ValidateCodeException e) { authenticationFailureHandler.onAuthenticationFailure(httpServletRequest, httpServletResponse, e); return; } } filterChain.doFilter(httpServletRequest, httpServletResponse); } private void validateCode(ServletWebRequest servletWebRequest) throws ServletRequestBindingException { ImageCode codeInSession = (ImageCode) sessionStrategy.getAttribute(servletWebRequest, ValidateController.SESSION_KEY_IMAGE_CODE); String codeInRequest = ServletRequestUtils.getStringParameter(servletWebRequest.getRequest(), "imageCode"); if (StringUtils.isBlank(codeInRequest)) { throw new ValidateCodeException("验证码不能为空!"); } if (codeInSession == null) { throw new ValidateCodeException("验证码不存在!"); } if (codeInSession.isExpire()) { sessionStrategy.removeAttribute(servletWebRequest, ValidateController.SESSION_KEY_IMAGE_CODE); throw new ValidateCodeException("验证码已过期!"); } if (!StringUtils.equalsIgnoreCase(codeInSession.getCode(), codeInRequest)) { throw new ValidateCodeException("验证码不正确!"); } sessionStrategy.removeAttribute(servletWebRequest, ValidateController.SESSION_KEY_IMAGE_CODE); } } ================================================ FILE: 60.Spring-Security-Logout/src/main/java/cc/mrbird/validate/smscode/SmsAuthenticationConfig.java ================================================ package cc.mrbird.validate.smscode; import cc.mrbird.security.browser.UserDetailService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.SecurityConfigurerAdapter; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.web.DefaultSecurityFilterChain; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.security.web.authentication.AuthenticationSuccessHandler; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.stereotype.Component; @Component public class SmsAuthenticationConfig extends SecurityConfigurerAdapter { @Autowired private AuthenticationSuccessHandler authenticationSuccessHandler; @Autowired private AuthenticationFailureHandler authenticationFailureHandler; @Autowired private UserDetailService userDetailService; @Override public void configure(HttpSecurity http) throws Exception { SmsAuthenticationFilter smsAuthenticationFilter = new SmsAuthenticationFilter(); smsAuthenticationFilter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class)); smsAuthenticationFilter.setAuthenticationSuccessHandler(authenticationSuccessHandler); smsAuthenticationFilter.setAuthenticationFailureHandler(authenticationFailureHandler); SmsAuthenticationProvider smsAuthenticationProvider = new SmsAuthenticationProvider(); smsAuthenticationProvider.setUserDetailService(userDetailService); http.authenticationProvider(smsAuthenticationProvider) .addFilterAfter(smsAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); } } ================================================ FILE: 60.Spring-Security-Logout/src/main/java/cc/mrbird/validate/smscode/SmsAuthenticationFilter.java ================================================ package cc.mrbird.validate.smscode; import org.springframework.security.authentication.AuthenticationServiceException; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.util.Assert; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class SmsAuthenticationFilter extends AbstractAuthenticationProcessingFilter { public static final String MOBILE_KEY = "mobile"; private String mobileParameter = MOBILE_KEY; private boolean postOnly = true; public SmsAuthenticationFilter() { super(new AntPathRequestMatcher("/login/mobile", "POST")); } public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { if (postOnly && !request.getMethod().equals("POST")) { throw new AuthenticationServiceException( "Authentication method not supported: " + request.getMethod()); } String mobile = obtainMobile(request); if (mobile == null) { mobile = ""; } mobile = mobile.trim(); SmsAuthenticationToken authRequest = new SmsAuthenticationToken(mobile); setDetails(request, authRequest); return this.getAuthenticationManager().authenticate(authRequest); } protected String obtainMobile(HttpServletRequest request) { return request.getParameter(mobileParameter); } protected void setDetails(HttpServletRequest request, SmsAuthenticationToken authRequest) { authRequest.setDetails(authenticationDetailsSource.buildDetails(request)); } public void setMobileParameter(String mobileParameter) { Assert.hasText(mobileParameter, "mobile parameter must not be empty or null"); this.mobileParameter = mobileParameter; } public void setPostOnly(boolean postOnly) { this.postOnly = postOnly; } public final String getMobileParameter() { return mobileParameter; } } ================================================ FILE: 60.Spring-Security-Logout/src/main/java/cc/mrbird/validate/smscode/SmsAuthenticationProvider.java ================================================ package cc.mrbird.validate.smscode; import cc.mrbird.security.browser.UserDetailService; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.InternalAuthenticationServiceException; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.userdetails.UserDetails; public class SmsAuthenticationProvider implements AuthenticationProvider { private UserDetailService userDetailService; @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { SmsAuthenticationToken authenticationToken = (SmsAuthenticationToken) authentication; UserDetails userDetails = userDetailService.loadUserByUsername((String) authenticationToken.getPrincipal()); if (userDetails == null) throw new InternalAuthenticationServiceException("未找到与该手机号对应的用户"); SmsAuthenticationToken authenticationResult = new SmsAuthenticationToken(userDetails, userDetails.getAuthorities()); authenticationResult.setDetails(authenticationToken.getDetails()); return authenticationResult; } @Override public boolean supports(Class aClass) { return SmsAuthenticationToken.class.isAssignableFrom(aClass); } public UserDetailService getUserDetailService() { return userDetailService; } public void setUserDetailService(UserDetailService userDetailService) { this.userDetailService = userDetailService; } } ================================================ FILE: 60.Spring-Security-Logout/src/main/java/cc/mrbird/validate/smscode/SmsAuthenticationToken.java ================================================ package cc.mrbird.validate.smscode; import org.springframework.security.authentication.AbstractAuthenticationToken; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.SpringSecurityCoreVersion; import java.util.Collection; public class SmsAuthenticationToken extends AbstractAuthenticationToken { private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID; private final Object principal; public SmsAuthenticationToken(String mobile) { super(null); this.principal = mobile; setAuthenticated(false); } public SmsAuthenticationToken(Object principal, Collection authorities) { super(authorities); this.principal = principal; super.setAuthenticated(true); // must use super, as we override } @Override public Object getCredentials() { return null; } public Object getPrincipal() { return this.principal; } public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException { if (isAuthenticated) { throw new IllegalArgumentException( "Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead"); } super.setAuthenticated(false); } @Override public void eraseCredentials() { super.eraseCredentials(); } } ================================================ FILE: 60.Spring-Security-Logout/src/main/java/cc/mrbird/validate/smscode/SmsCode.java ================================================ package cc.mrbird.validate.smscode; import java.time.LocalDateTime; public class SmsCode { private String code; private LocalDateTime expireTime; public SmsCode(String code, int expireIn) { this.code = code; this.expireTime = LocalDateTime.now().plusSeconds(expireIn); } public SmsCode(String code, LocalDateTime expireTime) { this.code = code; this.expireTime = expireTime; } boolean isExpire() { return LocalDateTime.now().isAfter(expireTime); } public String getCode() { return code; } public void setCode(String code) { this.code = code; } public LocalDateTime getExpireTime() { return expireTime; } public void setExpireTime(LocalDateTime expireTime) { this.expireTime = expireTime; } } ================================================ FILE: 60.Spring-Security-Logout/src/main/java/cc/mrbird/validate/smscode/SmsCodeFilter.java ================================================ package cc.mrbird.validate.smscode; import cc.mrbird.validate.code.ValidateCodeException; import cc.mrbird.web.controller.ValidateController; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.social.connect.web.HttpSessionSessionStrategy; import org.springframework.social.connect.web.SessionStrategy; import org.springframework.stereotype.Component; import org.springframework.web.bind.ServletRequestBindingException; import org.springframework.web.bind.ServletRequestUtils; import org.springframework.web.context.request.ServletWebRequest; import org.springframework.web.filter.OncePerRequestFilter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @Component public class SmsCodeFilter extends OncePerRequestFilter { @Autowired private AuthenticationFailureHandler authenticationFailureHandler; private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy(); @Override protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException { if (StringUtils.equalsIgnoreCase("/login/mobile", httpServletRequest.getRequestURI()) && StringUtils.equalsIgnoreCase(httpServletRequest.getMethod(), "post")) { try { validateCode(new ServletWebRequest(httpServletRequest)); } catch (ValidateCodeException e) { authenticationFailureHandler.onAuthenticationFailure(httpServletRequest, httpServletResponse, e); return; } } filterChain.doFilter(httpServletRequest, httpServletResponse); } private void validateCode(ServletWebRequest servletWebRequest) throws ServletRequestBindingException { String smsCodeInRequest = ServletRequestUtils.getStringParameter(servletWebRequest.getRequest(), "smsCode"); String mobileInRequest = ServletRequestUtils.getStringParameter(servletWebRequest.getRequest(), "smsCode"); SmsCode codeInSession = (SmsCode) sessionStrategy.getAttribute(servletWebRequest, ValidateController.SESSION_KEY_SMS_CODE + mobileInRequest); if (StringUtils.isBlank(smsCodeInRequest)) { throw new ValidateCodeException("验证码不能为空!"); } if (codeInSession == null) { throw new ValidateCodeException("验证码不存在!"); } if (codeInSession.isExpire()) { sessionStrategy.removeAttribute(servletWebRequest, ValidateController.SESSION_KEY_IMAGE_CODE); throw new ValidateCodeException("验证码已过期!"); } if (!StringUtils.equalsIgnoreCase(codeInSession.getCode(), smsCodeInRequest)) { throw new ValidateCodeException("验证码不正确!"); } sessionStrategy.removeAttribute(servletWebRequest, ValidateController.SESSION_KEY_IMAGE_CODE); } } ================================================ FILE: 60.Spring-Security-Logout/src/main/java/cc/mrbird/web/controller/BrowserSecurityController.java ================================================ package cc.mrbird.web.controller; import org.springframework.http.HttpStatus; import org.springframework.security.web.DefaultRedirectStrategy; import org.springframework.security.web.RedirectStrategy; import org.springframework.security.web.savedrequest.HttpSessionRequestCache; import org.springframework.security.web.savedrequest.RequestCache; import org.springframework.security.web.savedrequest.SavedRequest; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @author MrBird */ @RestController public class BrowserSecurityController { private RequestCache requestCache = new HttpSessionRequestCache(); private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy(); @GetMapping("/authentication/require") @ResponseStatus(HttpStatus.UNAUTHORIZED) public String requireAuthentication(HttpServletRequest request, HttpServletResponse response) throws IOException { SavedRequest savedRequest = requestCache.getRequest(request, response); if (savedRequest != null) { String targetUrl = savedRequest.getRedirectUrl(); if (StringUtils.endsWithIgnoreCase(targetUrl, ".html")) redirectStrategy.sendRedirect(request, response, "/login.html"); } return "访问的资源需要身份认证!"; } @GetMapping("/session/invalid") @ResponseStatus(HttpStatus.UNAUTHORIZED) public String sessionInvalid() { return "session已失效,请重新认证"; } @GetMapping("/signout/success") public String signout() { return "退出成功,请重新登录"; } } ================================================ FILE: 60.Spring-Security-Logout/src/main/java/cc/mrbird/web/controller/TestController.java ================================================ package cc.mrbird.web.controller; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class TestController { @GetMapping("hello") public String hello() { return "hello spring security"; } @GetMapping("index") public Object index(Authentication authentication) { // return SecurityContextHolder.getContext().getAuthentication(); return authentication; } } ================================================ FILE: 60.Spring-Security-Logout/src/main/java/cc/mrbird/web/controller/ValidateController.java ================================================ package cc.mrbird.web.controller; import cc.mrbird.validate.code.ImageCode; import cc.mrbird.validate.smscode.SmsCode; import org.apache.commons.lang3.RandomStringUtils; import org.springframework.social.connect.web.HttpSessionSessionStrategy; import org.springframework.social.connect.web.SessionStrategy; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.context.request.ServletWebRequest; import javax.imageio.ImageIO; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.awt.*; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.Random; @RestController public class ValidateController { public final static String SESSION_KEY_IMAGE_CODE = "SESSION_KEY_IMAGE_CODE"; public final static String SESSION_KEY_SMS_CODE = "SESSION_KEY_SMS_CODE"; private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy(); @GetMapping("/code/image") public void createCode(HttpServletRequest request, HttpServletResponse response) throws IOException { ImageCode imageCode = createImageCode(); ImageCode codeInRedis = new ImageCode(null,imageCode.getCode(),imageCode.getExpireTime()); sessionStrategy.setAttribute(new ServletWebRequest(request), SESSION_KEY_IMAGE_CODE, codeInRedis); ImageIO.write(imageCode.getImage(), "jpeg", response.getOutputStream()); } @GetMapping("/code/sms") public void createSmsCode(HttpServletRequest request, HttpServletResponse response, String mobile) { SmsCode smsCode = createSMSCode(); sessionStrategy.setAttribute(new ServletWebRequest(request), SESSION_KEY_SMS_CODE + mobile, smsCode); // 输出验证码到控制台代替短信发送服务 System.out.println("您的登录验证码为:" + smsCode.getCode() + ",有效时间为60秒"); } private SmsCode createSMSCode() { String code = RandomStringUtils.randomNumeric(6); return new SmsCode(code, 60); } private ImageCode createImageCode() { int width = 100; // 验证码图片宽度 int height = 36; // 验证码图片长度 int length = 4; // 验证码位数 int expireIn = 60; // 验证码有效时间 60s BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); Graphics g = image.getGraphics(); Random random = new Random(); g.setColor(getRandColor(200, 250)); g.fillRect(0, 0, width, height); g.setFont(new Font("Times New Roman", Font.ITALIC, 20)); g.setColor(getRandColor(160, 200)); for (int i = 0; i < 155; i++) { int x = random.nextInt(width); int y = random.nextInt(height); int xl = random.nextInt(12); int yl = random.nextInt(12); g.drawLine(x, y, x + xl, y + yl); } StringBuilder sRand = new StringBuilder(); for (int i = 0; i < length; i++) { String rand = String.valueOf(random.nextInt(10)); sRand.append(rand); g.setColor(new Color(20 + random.nextInt(110), 20 + random.nextInt(110), 20 + random.nextInt(110))); g.drawString(rand, 13 * i + 6, 16); } g.dispose(); return new ImageCode(image, sRand.toString(), expireIn); } private Color getRandColor(int fc, int bc) { Random random = new Random(); 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); } } ================================================ FILE: 60.Spring-Security-Logout/src/main/resources/application.yml ================================================ security: basic: enabled: true server: session: timeout: 3600 spring: session: store-type: redis ================================================ FILE: 60.Spring-Security-Logout/src/main/resources/resources/css/login.css ================================================ .login-page { width: 360px; padding: 8% 0 0; margin: auto; } .form { position: relative; z-index: 1; background: #ffffff; max-width: 360px; margin: 0 auto 100px; padding: 45px; text-align: center; box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.2), 0 5px 5px 0 rgba(0, 0, 0, 0.24); } .form input { outline: 0; background: #f2f2f2; width: 100%; border: 0; margin: 0 0 15px; padding: 15px; box-sizing: border-box; font-size: 14px; } .form button { text-transform: uppercase; outline: 0; background: #4caf50; width: 100%; border: 0; padding: 15px; color: #ffffff; font-size: 14px; -webkit-transition: all 0.3 ease; transition: all 0.3 ease; cursor: pointer; } .form button:hover, .form button:active, .form button:focus { background: #43a047; } .form .message { margin: 15px 0 0; color: #b3b3b3; font-size: 12px; } .form .message a { color: #4caf50; text-decoration: none; } .form .register-form { display: none; } .container { position: relative; z-index: 1; max-width: 300px; margin: 0 auto; } .container:before, .container:after { content: ""; display: block; clear: both; } .container .info { margin: 50px auto; text-align: center; } .container .info h1 { margin: 0 0 15px; padding: 0; font-size: 36px; font-weight: 300; color: #1a1a1a; } .container .info span { color: #4d4d4d; font-size: 12px; } .container .info span a { color: #000000; text-decoration: none; } .container .info span .fa { color: #ef3b3a; } body { background: #76b852; /* fallback for old browsers */ background: -webkit-linear-gradient(right, #76b852, #8dc26f); background: -moz-linear-gradient(right, #76b852, #8dc26f); background: -o-linear-gradient(right, #76b852, #8dc26f); background: linear-gradient(to left, #76b852, #8dc26f); font-family: Lato,"PingFang SC","Microsoft YaHei",sans-serif; } ================================================ FILE: 60.Spring-Security-Logout/src/main/resources/resources/login.html ================================================ 登录 ================================================ FILE: 61.Spring-security-Permission/pom.xml ================================================ 4.0.0 cc.mrbird Security 1.0-SNAPSHOT jar Security Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.14.RELEASE UTF-8 UTF-8 1.8 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-security org.springframework.social spring-social-config org.apache.commons commons-lang3 3.7 org.springframework.session spring-session org.springframework.boot spring-boot-starter-data-redis org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 61.Spring-security-Permission/src/main/java/cc/mrbird/SecurityApplication.java ================================================ package cc.mrbird; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class SecurityApplication { public static void main(String[] args) { SpringApplication.run(SecurityApplication.class, args); } } ================================================ FILE: 61.Spring-security-Permission/src/main/java/cc/mrbird/domain/MyUser.java ================================================ package cc.mrbird.domain; import java.io.Serializable; public class MyUser implements Serializable { private static final long serialVersionUID = 3497935890426858541L; private String userName; private String password; private boolean accountNonExpired = true; private boolean accountNonLocked= true; private boolean credentialsNonExpired= true; private boolean enabled= true; public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public boolean isAccountNonExpired() { return accountNonExpired; } public void setAccountNonExpired(boolean accountNonExpired) { this.accountNonExpired = accountNonExpired; } public boolean isAccountNonLocked() { return accountNonLocked; } public void setAccountNonLocked(boolean accountNonLocked) { this.accountNonLocked = accountNonLocked; } public boolean isCredentialsNonExpired() { return credentialsNonExpired; } public void setCredentialsNonExpired(boolean credentialsNonExpired) { this.credentialsNonExpired = credentialsNonExpired; } public boolean isEnabled() { return enabled; } public void setEnabled(boolean enabled) { this.enabled = enabled; } } ================================================ FILE: 61.Spring-security-Permission/src/main/java/cc/mrbird/handler/MyAuthenticationAccessDeniedHandler.java ================================================ package cc.mrbird.handler; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.http.HttpStatus; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.web.DefaultRedirectStrategy; import org.springframework.security.web.RedirectStrategy; import org.springframework.security.web.access.AccessDeniedHandler; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @Component public class MyAuthenticationAccessDeniedHandler implements AccessDeniedHandler { @Override public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException { response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value()); response.setContentType("application/json;charset=utf-8"); response.getWriter().write("很抱歉,您没有该访问权限"); } } ================================================ FILE: 61.Spring-security-Permission/src/main/java/cc/mrbird/handler/MyAuthenticationFailureHandler.java ================================================ package cc.mrbird.handler; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.stereotype.Component; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @Component public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler { @Autowired private ObjectMapper mapper; @Override public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException { response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value()); response.setContentType("application/json;charset=utf-8"); response.getWriter().write(mapper.writeValueAsString(exception.getMessage())); } } ================================================ FILE: 61.Spring-security-Permission/src/main/java/cc/mrbird/handler/MyAuthenticationSucessHandler.java ================================================ package cc.mrbird.handler; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.Authentication; import org.springframework.security.web.DefaultRedirectStrategy; import org.springframework.security.web.RedirectStrategy; import org.springframework.security.web.authentication.AuthenticationSuccessHandler; import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; import org.springframework.security.web.savedrequest.HttpSessionRequestCache; import org.springframework.security.web.savedrequest.RequestCache; import org.springframework.security.web.savedrequest.SavedRequest; import org.springframework.stereotype.Component; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @Component public class MyAuthenticationSucessHandler implements AuthenticationSuccessHandler { // private RequestCache requestCache = new HttpSessionRequestCache(); private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy(); // // @Autowired // private ObjectMapper mapper; @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException { // response.setContentType("application/json;charset=utf-8"); // response.getWriter().write(mapper.writeValueAsString(authentication)); // SavedRequest savedRequest = requestCache.getRequest(request, response); // System.out.println(savedRequest.getRedirectUrl()); // redirectStrategy.sendRedirect(request, response, savedRequest.getRedirectUrl()); redirectStrategy.sendRedirect(request, response, "/index"); } } ================================================ FILE: 61.Spring-security-Permission/src/main/java/cc/mrbird/handler/MyLogOutSuccessHandler.java ================================================ package cc.mrbird.handler; import org.springframework.http.HttpStatus; import org.springframework.security.core.Authentication; import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; import org.springframework.stereotype.Component; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @author MrBird */ @Component public class MyLogOutSuccessHandler implements LogoutSuccessHandler { @Override public void onLogoutSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException { httpServletResponse.setStatus(HttpStatus.UNAUTHORIZED.value()); httpServletResponse.setContentType("application/json;charset=utf-8"); httpServletResponse.getWriter().write("退出成功,请重新登录"); } } ================================================ FILE: 61.Spring-security-Permission/src/main/java/cc/mrbird/security/browser/BrowserSecurityConfig.java ================================================ package cc.mrbird.security.browser; import cc.mrbird.handler.MyAuthenticationAccessDeniedHandler; import cc.mrbird.handler.MyAuthenticationFailureHandler; import cc.mrbird.handler.MyAuthenticationSucessHandler; import cc.mrbird.handler.MyLogOutSuccessHandler; import cc.mrbird.session.MySessionExpiredStrategy; import cc.mrbird.validate.code.ValidateCodeFilter; import cc.mrbird.validate.smscode.SmsAuthenticationConfig; import cc.mrbird.validate.smscode.SmsCodeFilter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; @Configuration @EnableGlobalMethodSecurity(prePostEnabled = true) public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private MyAuthenticationSucessHandler authenticationSucessHandler; @Autowired private MyAuthenticationFailureHandler authenticationFailureHandler; @Autowired private MyAuthenticationAccessDeniedHandler authenticationAccessDeniedHandler; @Autowired private ValidateCodeFilter validateCodeFilter; @Autowired private SmsCodeFilter smsCodeFilter; @Autowired private SmsAuthenticationConfig smsAuthenticationConfig; @Autowired private MySessionExpiredStrategy sessionExpiredStrategy; @Autowired private MyLogOutSuccessHandler logOutSuccessHandler; @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Override protected void configure(HttpSecurity http) throws Exception { http.exceptionHandling() .accessDeniedHandler(authenticationAccessDeniedHandler) .and() .addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class) // 添加验证码校验过滤器 .addFilterBefore(smsCodeFilter,UsernamePasswordAuthenticationFilter.class) // 添加短信验证码校验过滤器 .formLogin() // 表单登录 // http.httpBasic() // HTTP Basic .loginPage("/authentication/require") // 登录跳转 URL .loginProcessingUrl("/login") // 处理表单登录 URL .successHandler(authenticationSucessHandler) // 处理登录成功 .failureHandler(authenticationFailureHandler) // 处理登录失败 .and() .authorizeRequests() // 授权配置 .antMatchers("/authentication/require", "/login.html", "/code/image","/code/sms","/session/invalid", "/signout/success").permitAll() // 无需认证的请求路径 .anyRequest() // 所有请求 .authenticated() // 都需要认证 .and() .sessionManagement() // 添加 Session管理器 .invalidSessionUrl("/session/invalid") // Session失效后跳转到这个链接 .maximumSessions(1) .maxSessionsPreventsLogin(true) .expiredSessionStrategy(sessionExpiredStrategy) .and() .and() .logout() .logoutUrl("/signout") // .logoutSuccessUrl("/signout/success") .logoutSuccessHandler(logOutSuccessHandler) .deleteCookies("JSESSIONID") .and() .csrf().disable() .apply(smsAuthenticationConfig); // 将短信验证码认证配置加到 Spring Security 中 } } ================================================ FILE: 61.Spring-security-Permission/src/main/java/cc/mrbird/security/browser/UserDetailService.java ================================================ package cc.mrbird.security.browser; import cc.mrbird.domain.MyUser; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.crypto.password.PasswordEncoder; import java.util.ArrayList; import java.util.List; @Configuration public class UserDetailService implements UserDetailsService { @Autowired private PasswordEncoder passwordEncoder; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { // 模拟一个用户,替代数据库获取逻辑 MyUser user = new MyUser(); user.setUserName(username); user.setPassword(this.passwordEncoder.encode("123456")); // 输出加密后的密码 System.out.println(user.getPassword()); List authorities = new ArrayList<>(); if (StringUtils.equalsIgnoreCase("mrbird", username)) { authorities = AuthorityUtils.commaSeparatedStringToAuthorityList("admin"); } else { authorities = AuthorityUtils.commaSeparatedStringToAuthorityList("test"); } return new User(username, user.getPassword(), user.isEnabled(), user.isAccountNonExpired(), user.isCredentialsNonExpired(), user.isAccountNonLocked(), authorities); } } ================================================ FILE: 61.Spring-security-Permission/src/main/java/cc/mrbird/session/MySessionExpiredStrategy.java ================================================ package cc.mrbird.session; import org.springframework.http.HttpStatus; import org.springframework.security.web.session.SessionInformationExpiredEvent; import org.springframework.security.web.session.SessionInformationExpiredStrategy; import org.springframework.stereotype.Component; import javax.servlet.ServletException; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @author MrBird */ @Component public class MySessionExpiredStrategy implements SessionInformationExpiredStrategy { @Override public void onExpiredSessionDetected(SessionInformationExpiredEvent event) throws IOException, ServletException { HttpServletResponse response = event.getResponse(); response.setStatus(HttpStatus.UNAUTHORIZED.value()); response.setContentType("application/json;charset=utf-8"); response.getWriter().write("您的账号已经在别的地方登录,当前登录已失效。如果密码遭到泄露,请立即修改密码!"); } } ================================================ FILE: 61.Spring-security-Permission/src/main/java/cc/mrbird/validate/code/ImageCode.java ================================================ package cc.mrbird.validate.code; import java.awt.image.BufferedImage; import java.io.Serializable; import java.time.LocalDateTime; public class ImageCode implements Serializable { private static final long serialVersionUID = -7831615057416168810L; private BufferedImage image; private String code; private LocalDateTime expireTime; public ImageCode(BufferedImage image, String code, int expireIn) { this.image = image; this.code = code; this.expireTime = LocalDateTime.now().plusSeconds(expireIn); } public ImageCode(BufferedImage image, String code, LocalDateTime expireTime) { this.image = image; this.code = code; this.expireTime = expireTime; } boolean isExpire() { return LocalDateTime.now().isAfter(expireTime); } public BufferedImage getImage() { return image; } public void setImage(BufferedImage image) { this.image = image; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } public LocalDateTime getExpireTime() { return expireTime; } public void setExpireTime(LocalDateTime expireTime) { this.expireTime = expireTime; } } ================================================ FILE: 61.Spring-security-Permission/src/main/java/cc/mrbird/validate/code/ValidateCodeException.java ================================================ package cc.mrbird.validate.code; import org.springframework.security.core.AuthenticationException; public class ValidateCodeException extends AuthenticationException { private static final long serialVersionUID = 5022575393500654458L; public ValidateCodeException(String message) { super(message); } } ================================================ FILE: 61.Spring-security-Permission/src/main/java/cc/mrbird/validate/code/ValidateCodeFilter.java ================================================ package cc.mrbird.validate.code; import cc.mrbird.web.controller.ValidateController; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.social.connect.web.HttpSessionSessionStrategy; import org.springframework.social.connect.web.SessionStrategy; import org.springframework.stereotype.Component; import org.springframework.web.bind.ServletRequestBindingException; import org.springframework.web.bind.ServletRequestUtils; import org.springframework.web.context.request.ServletWebRequest; import org.springframework.web.filter.OncePerRequestFilter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @Component public class ValidateCodeFilter extends OncePerRequestFilter { @Autowired private AuthenticationFailureHandler authenticationFailureHandler; private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy(); @Override protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException { if (StringUtils.equalsIgnoreCase("/login", httpServletRequest.getRequestURI()) && StringUtils.equalsIgnoreCase(httpServletRequest.getMethod(), "post")) { try { validateCode(new ServletWebRequest(httpServletRequest)); } catch (ValidateCodeException e) { authenticationFailureHandler.onAuthenticationFailure(httpServletRequest, httpServletResponse, e); return; } } filterChain.doFilter(httpServletRequest, httpServletResponse); } private void validateCode(ServletWebRequest servletWebRequest) throws ServletRequestBindingException { ImageCode codeInSession = (ImageCode) sessionStrategy.getAttribute(servletWebRequest, ValidateController.SESSION_KEY_IMAGE_CODE); String codeInRequest = ServletRequestUtils.getStringParameter(servletWebRequest.getRequest(), "imageCode"); if (StringUtils.isBlank(codeInRequest)) { throw new ValidateCodeException("验证码不能为空!"); } if (codeInSession == null) { throw new ValidateCodeException("验证码不存在!"); } if (codeInSession.isExpire()) { sessionStrategy.removeAttribute(servletWebRequest, ValidateController.SESSION_KEY_IMAGE_CODE); throw new ValidateCodeException("验证码已过期!"); } if (!StringUtils.equalsIgnoreCase(codeInSession.getCode(), codeInRequest)) { throw new ValidateCodeException("验证码不正确!"); } sessionStrategy.removeAttribute(servletWebRequest, ValidateController.SESSION_KEY_IMAGE_CODE); } } ================================================ FILE: 61.Spring-security-Permission/src/main/java/cc/mrbird/validate/smscode/SmsAuthenticationConfig.java ================================================ package cc.mrbird.validate.smscode; import cc.mrbird.security.browser.UserDetailService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.SecurityConfigurerAdapter; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.web.DefaultSecurityFilterChain; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.security.web.authentication.AuthenticationSuccessHandler; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.stereotype.Component; @Component public class SmsAuthenticationConfig extends SecurityConfigurerAdapter { @Autowired private AuthenticationSuccessHandler authenticationSuccessHandler; @Autowired private AuthenticationFailureHandler authenticationFailureHandler; @Autowired private UserDetailService userDetailService; @Override public void configure(HttpSecurity http) throws Exception { SmsAuthenticationFilter smsAuthenticationFilter = new SmsAuthenticationFilter(); smsAuthenticationFilter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class)); smsAuthenticationFilter.setAuthenticationSuccessHandler(authenticationSuccessHandler); smsAuthenticationFilter.setAuthenticationFailureHandler(authenticationFailureHandler); SmsAuthenticationProvider smsAuthenticationProvider = new SmsAuthenticationProvider(); smsAuthenticationProvider.setUserDetailService(userDetailService); http.authenticationProvider(smsAuthenticationProvider) .addFilterAfter(smsAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); } } ================================================ FILE: 61.Spring-security-Permission/src/main/java/cc/mrbird/validate/smscode/SmsAuthenticationFilter.java ================================================ package cc.mrbird.validate.smscode; import org.springframework.security.authentication.AuthenticationServiceException; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.util.Assert; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class SmsAuthenticationFilter extends AbstractAuthenticationProcessingFilter { public static final String MOBILE_KEY = "mobile"; private String mobileParameter = MOBILE_KEY; private boolean postOnly = true; public SmsAuthenticationFilter() { super(new AntPathRequestMatcher("/login/mobile", "POST")); } public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { if (postOnly && !request.getMethod().equals("POST")) { throw new AuthenticationServiceException( "Authentication method not supported: " + request.getMethod()); } String mobile = obtainMobile(request); if (mobile == null) { mobile = ""; } mobile = mobile.trim(); SmsAuthenticationToken authRequest = new SmsAuthenticationToken(mobile); setDetails(request, authRequest); return this.getAuthenticationManager().authenticate(authRequest); } protected String obtainMobile(HttpServletRequest request) { return request.getParameter(mobileParameter); } protected void setDetails(HttpServletRequest request, SmsAuthenticationToken authRequest) { authRequest.setDetails(authenticationDetailsSource.buildDetails(request)); } public void setMobileParameter(String mobileParameter) { Assert.hasText(mobileParameter, "mobile parameter must not be empty or null"); this.mobileParameter = mobileParameter; } public void setPostOnly(boolean postOnly) { this.postOnly = postOnly; } public final String getMobileParameter() { return mobileParameter; } } ================================================ FILE: 61.Spring-security-Permission/src/main/java/cc/mrbird/validate/smscode/SmsAuthenticationProvider.java ================================================ package cc.mrbird.validate.smscode; import cc.mrbird.security.browser.UserDetailService; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.InternalAuthenticationServiceException; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.userdetails.UserDetails; public class SmsAuthenticationProvider implements AuthenticationProvider { private UserDetailService userDetailService; @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { SmsAuthenticationToken authenticationToken = (SmsAuthenticationToken) authentication; UserDetails userDetails = userDetailService.loadUserByUsername((String) authenticationToken.getPrincipal()); if (userDetails == null) throw new InternalAuthenticationServiceException("未找到与该手机号对应的用户"); SmsAuthenticationToken authenticationResult = new SmsAuthenticationToken(userDetails, userDetails.getAuthorities()); authenticationResult.setDetails(authenticationToken.getDetails()); return authenticationResult; } @Override public boolean supports(Class aClass) { return SmsAuthenticationToken.class.isAssignableFrom(aClass); } public UserDetailService getUserDetailService() { return userDetailService; } public void setUserDetailService(UserDetailService userDetailService) { this.userDetailService = userDetailService; } } ================================================ FILE: 61.Spring-security-Permission/src/main/java/cc/mrbird/validate/smscode/SmsAuthenticationToken.java ================================================ package cc.mrbird.validate.smscode; import org.springframework.security.authentication.AbstractAuthenticationToken; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.SpringSecurityCoreVersion; import java.util.Collection; public class SmsAuthenticationToken extends AbstractAuthenticationToken { private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID; private final Object principal; public SmsAuthenticationToken(String mobile) { super(null); this.principal = mobile; setAuthenticated(false); } public SmsAuthenticationToken(Object principal, Collection authorities) { super(authorities); this.principal = principal; super.setAuthenticated(true); // must use super, as we override } @Override public Object getCredentials() { return null; } public Object getPrincipal() { return this.principal; } public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException { if (isAuthenticated) { throw new IllegalArgumentException( "Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead"); } super.setAuthenticated(false); } @Override public void eraseCredentials() { super.eraseCredentials(); } } ================================================ FILE: 61.Spring-security-Permission/src/main/java/cc/mrbird/validate/smscode/SmsCode.java ================================================ package cc.mrbird.validate.smscode; import java.time.LocalDateTime; public class SmsCode { private String code; private LocalDateTime expireTime; public SmsCode(String code, int expireIn) { this.code = code; this.expireTime = LocalDateTime.now().plusSeconds(expireIn); } public SmsCode(String code, LocalDateTime expireTime) { this.code = code; this.expireTime = expireTime; } boolean isExpire() { return LocalDateTime.now().isAfter(expireTime); } public String getCode() { return code; } public void setCode(String code) { this.code = code; } public LocalDateTime getExpireTime() { return expireTime; } public void setExpireTime(LocalDateTime expireTime) { this.expireTime = expireTime; } } ================================================ FILE: 61.Spring-security-Permission/src/main/java/cc/mrbird/validate/smscode/SmsCodeFilter.java ================================================ package cc.mrbird.validate.smscode; import cc.mrbird.validate.code.ValidateCodeException; import cc.mrbird.web.controller.ValidateController; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.social.connect.web.HttpSessionSessionStrategy; import org.springframework.social.connect.web.SessionStrategy; import org.springframework.stereotype.Component; import org.springframework.web.bind.ServletRequestBindingException; import org.springframework.web.bind.ServletRequestUtils; import org.springframework.web.context.request.ServletWebRequest; import org.springframework.web.filter.OncePerRequestFilter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @Component public class SmsCodeFilter extends OncePerRequestFilter { @Autowired private AuthenticationFailureHandler authenticationFailureHandler; private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy(); @Override protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException { if (StringUtils.equalsIgnoreCase("/login/mobile", httpServletRequest.getRequestURI()) && StringUtils.equalsIgnoreCase(httpServletRequest.getMethod(), "post")) { try { validateCode(new ServletWebRequest(httpServletRequest)); } catch (ValidateCodeException e) { authenticationFailureHandler.onAuthenticationFailure(httpServletRequest, httpServletResponse, e); return; } } filterChain.doFilter(httpServletRequest, httpServletResponse); } private void validateCode(ServletWebRequest servletWebRequest) throws ServletRequestBindingException { String smsCodeInRequest = ServletRequestUtils.getStringParameter(servletWebRequest.getRequest(), "smsCode"); String mobileInRequest = ServletRequestUtils.getStringParameter(servletWebRequest.getRequest(), "smsCode"); SmsCode codeInSession = (SmsCode) sessionStrategy.getAttribute(servletWebRequest, ValidateController.SESSION_KEY_SMS_CODE + mobileInRequest); if (StringUtils.isBlank(smsCodeInRequest)) { throw new ValidateCodeException("验证码不能为空!"); } if (codeInSession == null) { throw new ValidateCodeException("验证码不存在!"); } if (codeInSession.isExpire()) { sessionStrategy.removeAttribute(servletWebRequest, ValidateController.SESSION_KEY_IMAGE_CODE); throw new ValidateCodeException("验证码已过期!"); } if (!StringUtils.equalsIgnoreCase(codeInSession.getCode(), smsCodeInRequest)) { throw new ValidateCodeException("验证码不正确!"); } sessionStrategy.removeAttribute(servletWebRequest, ValidateController.SESSION_KEY_IMAGE_CODE); } } ================================================ FILE: 61.Spring-security-Permission/src/main/java/cc/mrbird/web/controller/BrowserSecurityController.java ================================================ package cc.mrbird.web.controller; import org.springframework.http.HttpStatus; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.web.DefaultRedirectStrategy; import org.springframework.security.web.RedirectStrategy; import org.springframework.security.web.savedrequest.HttpSessionRequestCache; import org.springframework.security.web.savedrequest.RequestCache; import org.springframework.security.web.savedrequest.SavedRequest; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @author MrBird */ @RestController public class BrowserSecurityController { private RequestCache requestCache = new HttpSessionRequestCache(); private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy(); @GetMapping("/authentication/require") @ResponseStatus(HttpStatus.UNAUTHORIZED) public String requireAuthentication(HttpServletRequest request, HttpServletResponse response) throws IOException { SavedRequest savedRequest = requestCache.getRequest(request, response); if (savedRequest != null) { String targetUrl = savedRequest.getRedirectUrl(); if (StringUtils.endsWithIgnoreCase(targetUrl, ".html")) redirectStrategy.sendRedirect(request, response, "/login.html"); } return "访问的资源需要身份认证!"; } @GetMapping("/session/invalid") @ResponseStatus(HttpStatus.UNAUTHORIZED) public String sessionInvalid() { return "session已失效,请重新认证"; } @GetMapping("/signout/success") public String signout() { return "退出成功,请重新登录"; } @GetMapping("/auth/admin") @PreAuthorize("hasAuthority('admin')") public String authenticationTest() { return "您拥有admin权限,可以查看"; } } ================================================ FILE: 61.Spring-security-Permission/src/main/java/cc/mrbird/web/controller/TestController.java ================================================ package cc.mrbird.web.controller; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class TestController { @GetMapping("hello") public String hello() { return "hello spring security"; } @GetMapping("index") public Object index(Authentication authentication) { // return SecurityContextHolder.getContext().getAuthentication(); return authentication; } } ================================================ FILE: 61.Spring-security-Permission/src/main/java/cc/mrbird/web/controller/ValidateController.java ================================================ package cc.mrbird.web.controller; import cc.mrbird.validate.code.ImageCode; import cc.mrbird.validate.smscode.SmsCode; import org.apache.commons.lang3.RandomStringUtils; import org.springframework.social.connect.web.HttpSessionSessionStrategy; import org.springframework.social.connect.web.SessionStrategy; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.context.request.ServletWebRequest; import javax.imageio.ImageIO; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.awt.*; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.Random; @RestController public class ValidateController { public final static String SESSION_KEY_IMAGE_CODE = "SESSION_KEY_IMAGE_CODE"; public final static String SESSION_KEY_SMS_CODE = "SESSION_KEY_SMS_CODE"; private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy(); @GetMapping("/code/image") public void createCode(HttpServletRequest request, HttpServletResponse response) throws IOException { ImageCode imageCode = createImageCode(); ImageCode codeInRedis = new ImageCode(null,imageCode.getCode(),imageCode.getExpireTime()); sessionStrategy.setAttribute(new ServletWebRequest(request), SESSION_KEY_IMAGE_CODE, codeInRedis); ImageIO.write(imageCode.getImage(), "jpeg", response.getOutputStream()); } @GetMapping("/code/sms") public void createSmsCode(HttpServletRequest request, HttpServletResponse response, String mobile) { SmsCode smsCode = createSMSCode(); sessionStrategy.setAttribute(new ServletWebRequest(request), SESSION_KEY_SMS_CODE + mobile, smsCode); // 输出验证码到控制台代替短信发送服务 System.out.println("您的登录验证码为:" + smsCode.getCode() + ",有效时间为60秒"); } private SmsCode createSMSCode() { String code = RandomStringUtils.randomNumeric(6); return new SmsCode(code, 60); } private ImageCode createImageCode() { int width = 100; // 验证码图片宽度 int height = 36; // 验证码图片长度 int length = 4; // 验证码位数 int expireIn = 60; // 验证码有效时间 60s BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); Graphics g = image.getGraphics(); Random random = new Random(); g.setColor(getRandColor(200, 250)); g.fillRect(0, 0, width, height); g.setFont(new Font("Times New Roman", Font.ITALIC, 20)); g.setColor(getRandColor(160, 200)); for (int i = 0; i < 155; i++) { int x = random.nextInt(width); int y = random.nextInt(height); int xl = random.nextInt(12); int yl = random.nextInt(12); g.drawLine(x, y, x + xl, y + yl); } StringBuilder sRand = new StringBuilder(); for (int i = 0; i < length; i++) { String rand = String.valueOf(random.nextInt(10)); sRand.append(rand); g.setColor(new Color(20 + random.nextInt(110), 20 + random.nextInt(110), 20 + random.nextInt(110))); g.drawString(rand, 13 * i + 6, 16); } g.dispose(); return new ImageCode(image, sRand.toString(), expireIn); } private Color getRandColor(int fc, int bc) { Random random = new Random(); 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); } } ================================================ FILE: 61.Spring-security-Permission/src/main/resources/application.yml ================================================ security: basic: enabled: true server: session: timeout: 3600 spring: session: store-type: redis ================================================ FILE: 61.Spring-security-Permission/src/main/resources/resources/css/login.css ================================================ .login-page { width: 360px; padding: 8% 0 0; margin: auto; } .form { position: relative; z-index: 1; background: #ffffff; max-width: 360px; margin: 0 auto 100px; padding: 45px; text-align: center; box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.2), 0 5px 5px 0 rgba(0, 0, 0, 0.24); } .form input { outline: 0; background: #f2f2f2; width: 100%; border: 0; margin: 0 0 15px; padding: 15px; box-sizing: border-box; font-size: 14px; } .form button { text-transform: uppercase; outline: 0; background: #4caf50; width: 100%; border: 0; padding: 15px; color: #ffffff; font-size: 14px; -webkit-transition: all 0.3 ease; transition: all 0.3 ease; cursor: pointer; } .form button:hover, .form button:active, .form button:focus { background: #43a047; } .form .message { margin: 15px 0 0; color: #b3b3b3; font-size: 12px; } .form .message a { color: #4caf50; text-decoration: none; } .form .register-form { display: none; } .container { position: relative; z-index: 1; max-width: 300px; margin: 0 auto; } .container:before, .container:after { content: ""; display: block; clear: both; } .container .info { margin: 50px auto; text-align: center; } .container .info h1 { margin: 0 0 15px; padding: 0; font-size: 36px; font-weight: 300; color: #1a1a1a; } .container .info span { color: #4d4d4d; font-size: 12px; } .container .info span a { color: #000000; text-decoration: none; } .container .info span .fa { color: #ef3b3a; } body { background: #76b852; /* fallback for old browsers */ background: -webkit-linear-gradient(right, #76b852, #8dc26f); background: -moz-linear-gradient(right, #76b852, #8dc26f); background: -o-linear-gradient(right, #76b852, #8dc26f); background: linear-gradient(to left, #76b852, #8dc26f); font-family: Lato,"PingFang SC","Microsoft YaHei",sans-serif; } ================================================ FILE: 61.Spring-security-Permission/src/main/resources/resources/login.html ================================================ 登录 ================================================ FILE: 62.Spring-Boot-Shiro-JWT/pom.xml ================================================ 4.0.0 org.springframework.boot spring-boot-starter-parent 2.1.0.RELEASE com.example demo 0.0.1-SNAPSHOT springboot-shiro-jwt-demo springboot整合shiro,jwt简单样例 1.8 org.springframework.boot spring-boot-starter-web org.apache.shiro shiro-spring 1.4.0 com.auth0 java-jwt 3.4.1 org.springframework.boot spring-boot-starter-aop org.apache.commons commons-lang3 org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 62.Spring-Boot-Shiro-JWT/src/main/java/com/example/demo/DemoApplication.java ================================================ package com.example.demo; import com.example.demo.properties.SystemProperties; import org.springframework.boot.Banner; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.context.properties.EnableConfigurationProperties; /** * * @author MrBird */ @SpringBootApplication @EnableConfigurationProperties(SystemProperties.class) public class DemoApplication { public static void main(String[] args) { new SpringApplicationBuilder(DemoApplication.class) .bannerMode(Banner.Mode.OFF) .run(args); } } ================================================ FILE: 62.Spring-Boot-Shiro-JWT/src/main/java/com/example/demo/authentication/JWTFilter.java ================================================ package com.example.demo.authentication; import com.example.demo.properties.SystemProperties; import com.example.demo.utils.SpringContextUtil; import org.apache.commons.lang3.StringUtils; import org.apache.shiro.authz.UnauthorizedException; import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; import org.springframework.util.AntPathMatcher; import org.springframework.web.bind.annotation.RequestMethod; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * * @author MrBird */ public class JWTFilter extends BasicHttpAuthenticationFilter { private Logger log = LoggerFactory.getLogger(this.getClass()); private static final String TOKEN = "Token"; private AntPathMatcher pathMatcher = new AntPathMatcher(); @Override protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws UnauthorizedException { HttpServletRequest httpServletRequest = (HttpServletRequest) request; SystemProperties properties = SpringContextUtil.getBean(SystemProperties.class); String[] anonUrl = StringUtils.splitByWholeSeparatorPreserveAllTokens(properties.getAnonUrl(), ","); boolean match = false; for (String u : anonUrl) { if (pathMatcher.match(u, httpServletRequest.getRequestURI())) match = true; } if (match) return true; if (isLoginAttempt(request, response)) { return executeLogin(request, response); } return false; } @Override protected boolean isLoginAttempt(ServletRequest request, ServletResponse response) { HttpServletRequest req = (HttpServletRequest) request; String token = req.getHeader(TOKEN); return token != null; } @Override protected boolean executeLogin(ServletRequest request, ServletResponse response) { HttpServletRequest httpServletRequest = (HttpServletRequest) request; String token = httpServletRequest.getHeader(TOKEN); JWTToken jwtToken = new JWTToken(token); try { getSubject(request, response).login(jwtToken); return true; } catch (Exception e) { log.error(e.getMessage()); return false; } } /** * 对跨域提供支持 */ @Override protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception { HttpServletRequest httpServletRequest = (HttpServletRequest) request; HttpServletResponse httpServletResponse = (HttpServletResponse) response; httpServletResponse.setHeader("Access-control-Allow-Origin", httpServletRequest.getHeader("Origin")); httpServletResponse.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE"); httpServletResponse.setHeader("Access-Control-Allow-Headers", httpServletRequest.getHeader("Access-Control-Request-Headers")); // 跨域时会首先发送一个 option请求,这里我们给 option请求直接返回正常状态 if (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())) { httpServletResponse.setStatus(HttpStatus.OK.value()); return false; } return super.preHandle(request, response); } } ================================================ FILE: 62.Spring-Boot-Shiro-JWT/src/main/java/com/example/demo/authentication/JWTToken.java ================================================ package com.example.demo.authentication; import org.apache.shiro.authc.AuthenticationToken; /** * JSON Web Token * * @author MrBird */ public class JWTToken implements AuthenticationToken { private static final long serialVersionUID = 1282057025599826155L; private String token; private String exipreAt; public JWTToken(String token) { this.token = token; } public JWTToken(String token, String exipreAt) { this.token = token; this.exipreAt = exipreAt; } @Override public Object getPrincipal() { return token; } @Override public Object getCredentials() { return token; } public String getToken() { return token; } public void setToken(String token) { this.token = token; } public String getExipreAt() { return exipreAt; } public void setExipreAt(String exipreAt) { this.exipreAt = exipreAt; } } ================================================ FILE: 62.Spring-Boot-Shiro-JWT/src/main/java/com/example/demo/authentication/JWTUtil.java ================================================ package com.example.demo.authentication; import com.auth0.jwt.JWT; import com.auth0.jwt.JWTVerifier; import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.exceptions.JWTDecodeException; import com.auth0.jwt.interfaces.DecodedJWT; import com.example.demo.properties.SystemProperties; import com.example.demo.utils.SpringContextUtil; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Date; /** * * @author MrBird */ public class JWTUtil { private static Logger log = LoggerFactory.getLogger(JWTUtil.class); private static final long EXPIRE_TIME = SpringContextUtil.getBean(SystemProperties.class).getJwtTimeOut() * 1000; /** * 校验 token是否正确 * * @param token 密钥 * @param secret 用户的密码 * @return 是否正确 */ public static boolean verify(String token, String username, String secret) { try { Algorithm algorithm = Algorithm.HMAC256(secret); JWTVerifier verifier = JWT.require(algorithm) .withClaim("username", username) .build(); verifier.verify(token); log.info("token is valid"); return true; } catch (Exception e) { log.info("token is invalid{}", e.getMessage()); return false; } } /** * 从 token中获取用户名 * * @return token中包含的用户名 */ public static String getUsername(String token) { try { DecodedJWT jwt = JWT.decode(token); return jwt.getClaim("username").asString(); } catch (JWTDecodeException e) { log.error("error:{}", e.getMessage()); return null; } } /** * 生成 token * * @param username 用户名 * @param secret 用户的密码 * @return token */ public static String sign(String username, String secret) { try { username = StringUtils.lowerCase(username); Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME); Algorithm algorithm = Algorithm.HMAC256(secret); return JWT.create() .withClaim("username", username) .withExpiresAt(date) .sign(algorithm); } catch (Exception e) { log.error("error:{}", e); return null; } } } ================================================ FILE: 62.Spring-Boot-Shiro-JWT/src/main/java/com/example/demo/authentication/ShiroConfig.java ================================================ package com.example.demo.authentication; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import javax.servlet.Filter; import java.util.LinkedHashMap; /** * Shiro 配置类 * * @author MrBird */ @Configuration public class ShiroConfig { @Bean public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); // 设置 securityManager shiroFilterFactoryBean.setSecurityManager(securityManager); // 在 Shiro过滤器链上加入 JWTFilter LinkedHashMap filters = new LinkedHashMap<>(); filters.put("jwt", new JWTFilter()); shiroFilterFactoryBean.setFilters(filters); LinkedHashMap filterChainDefinitionMap = new LinkedHashMap<>(); // 所有请求都要经过 jwt过滤器 filterChainDefinitionMap.put("/**", "jwt"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } @Bean public SecurityManager securityManager() { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); // 配置 SecurityManager,并注入 shiroRealm securityManager.setRealm(shiroRealm()); return securityManager; } @Bean public ShiroRealm shiroRealm() { // 配置 Realm return new ShiroRealm(); } @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) { AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); return authorizationAttributeSourceAdvisor; } } ================================================ FILE: 62.Spring-Boot-Shiro-JWT/src/main/java/com/example/demo/authentication/ShiroRealm.java ================================================ package com.example.demo.authentication; import com.example.demo.domain.User; import com.example.demo.utils.SystemUtils; import org.apache.commons.lang3.StringUtils; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; /** * 自定义实现 ShiroRealm,包含认证和授权两大模块 * * @author MrBird */ public class ShiroRealm extends AuthorizingRealm { @Override public boolean supports(AuthenticationToken token) { return token instanceof JWTToken; } /** * ` * 授权模块,获取用户角色和权限 * * @param token token * @return AuthorizationInfo 权限信息 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection token) { String username = JWTUtil.getUsername(token.toString()); User user = SystemUtils.getUser(username); SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(); // 获取用户角色集(模拟值,实际从数据库获取) simpleAuthorizationInfo.setRoles(user.getRole()); // 获取用户权限集(模拟值,实际从数据库获取) simpleAuthorizationInfo.setStringPermissions(user.getPermission()); return simpleAuthorizationInfo; } /** * 用户认证 * * @param authenticationToken 身份认证 token * @return AuthenticationInfo 身份认证信息 * @throws AuthenticationException 认证相关异常 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { // 这里的 token是从 JWTFilter 的 executeLogin 方法传递过来的,已经经过了解密 String token = (String) authenticationToken.getCredentials(); String username = JWTUtil.getUsername(token); if (StringUtils.isBlank(username)) throw new AuthenticationException("token校验不通过"); // 通过用户名查询用户信息 User user = SystemUtils.getUser(username); if (user == null) throw new AuthenticationException("用户名或密码错误"); if (!JWTUtil.verify(token, username, user.getPassword())) throw new AuthenticationException("token校验不通过"); return new SimpleAuthenticationInfo(token, token, "shiro_realm"); } } ================================================ FILE: 62.Spring-Boot-Shiro-JWT/src/main/java/com/example/demo/controller/LoginController.java ================================================ package com.example.demo.controller; import com.example.demo.authentication.JWTUtil; import com.example.demo.domain.Response; import com.example.demo.domain.User; import com.example.demo.exception.SystemException; import com.example.demo.properties.SystemProperties; import com.example.demo.utils.MD5Util; import com.example.demo.utils.SystemUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; import javax.validation.constraints.NotBlank; import java.util.HashMap; import java.util.Map; /** * @author MrBird */ @RestController @Validated public class LoginController { @Autowired private SystemProperties properties; @PostMapping("/login") public Response login( @NotBlank(message = "{required}") String username, @NotBlank(message = "{required}") String password, HttpServletRequest request) throws Exception { username = StringUtils.lowerCase(username); password = MD5Util.encrypt(username, password); final String errorMessage = "用户名或密码错误"; User user = SystemUtils.getUser(username); if (user == null) throw new SystemException(errorMessage); if (!StringUtils.equals(user.getPassword(), password)) throw new SystemException(errorMessage); // 生成 Token String token = JWTUtil.sign(username, password); Map userInfo = this.generateUserInfo(token, user); return new Response().message("认证成功").data(userInfo); } /** * 生成前端需要的用户信息,包括: * 1. token * 2. user * * @param token token * @param user 用户信息 * @return UserInfo */ private Map generateUserInfo(String token, User user) { String username = user.getUsername(); Map userInfo = new HashMap<>(); userInfo.put("token", token); user.setPassword("it's a secret"); userInfo.put("user", user); return userInfo; } } ================================================ FILE: 62.Spring-Boot-Shiro-JWT/src/main/java/com/example/demo/controller/TestController.java ================================================ package com.example.demo.controller; import org.apache.shiro.authz.annotation.RequiresPermissions; import org.apache.shiro.authz.annotation.RequiresRoles; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * @author MrBird */ @RestController @RequestMapping("test") public class TestController { /** * 需要登录才能访问 */ @GetMapping("/1") public String test1() { return "success"; } /** * 需要 admin 角色才能访问 */ @GetMapping("/2") @RequiresRoles("admin") public String test2() { return "success"; } /** * 需要 "user:add" 权限才能访问 */ @GetMapping("/3") @RequiresPermissions("user:add") public String test3() { return "success"; } } ================================================ FILE: 62.Spring-Boot-Shiro-JWT/src/main/java/com/example/demo/domain/Response.java ================================================ package com.example.demo.domain; import java.util.HashMap; /** * * @author MrBird */ public class Response extends HashMap { private static final long serialVersionUID = -8713837118340960775L; public Response message(String message) { this.put("message", message); return this; } public Response data(Object data) { this.put("data", data); return this; } @Override public Response put(String key, Object value) { super.put(key, value); return this; } } ================================================ FILE: 62.Spring-Boot-Shiro-JWT/src/main/java/com/example/demo/domain/User.java ================================================ package com.example.demo.domain; import java.io.Serializable; import java.util.Set; /** * @author MrBird */ public class User implements Serializable { private static final long serialVersionUID = -2731598327208972274L; private String username; private String password; private Set role; private Set permission; public User(String username, String password, Set role, Set permission) { this.username = username; this.password = password; this.role = role; this.permission = permission; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Set getRole() { return role; } public void setRole(Set role) { this.role = role; } public Set getPermission() { return permission; } public void setPermission(Set permission) { this.permission = permission; } } ================================================ FILE: 62.Spring-Boot-Shiro-JWT/src/main/java/com/example/demo/exception/SystemException.java ================================================ package com.example.demo.exception; /** * 系统内部异常 * * @author MrBird */ public class SystemException extends Exception { private static final long serialVersionUID = -994962710559017255L; public SystemException(String message) { super(message); } } ================================================ FILE: 62.Spring-Boot-Shiro-JWT/src/main/java/com/example/demo/handler/GlobalExceptionHandler.java ================================================ package com.example.demo.handler; import com.example.demo.domain.Response; import com.example.demo.exception.SystemException; import org.apache.commons.lang3.StringUtils; import org.apache.shiro.authz.UnauthorizedException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.http.HttpStatus; import org.springframework.validation.BindException; import org.springframework.validation.FieldError; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestControllerAdvice; import javax.validation.ConstraintViolation; import javax.validation.ConstraintViolationException; import javax.validation.Path; import java.util.List; import java.util.Set; /** * * @author MrBird */ @RestControllerAdvice @Order(value = Ordered.HIGHEST_PRECEDENCE) public class GlobalExceptionHandler { private Logger log = LoggerFactory.getLogger(this.getClass()); @ExceptionHandler(value = Exception.class) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public Response handleException(Exception e) { log.error("系统内部异常,异常信息:", e); return new Response().message("系统内部异常"); } @ExceptionHandler(value = SystemException.class) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public Response handleParamsInvalidException(SystemException e) { log.error("系统错误:{}", e.getMessage()); return new Response().message(e.getMessage()); } /** * 统一处理请求参数校验(实体对象传参) * * @param e BindException * @return FebsResponse */ @ExceptionHandler(BindException.class) @ResponseStatus(HttpStatus.BAD_REQUEST) public Response validExceptionHandler(BindException e) { StringBuilder message = new StringBuilder(); List fieldErrors = e.getBindingResult().getFieldErrors(); for (FieldError error : fieldErrors) { message.append(error.getField()).append(error.getDefaultMessage()).append(","); } message = new StringBuilder(message.substring(0, message.length() - 1)); return new Response().message(message.toString()); } /** * 统一处理请求参数校验(普通传参) * * @param e ConstraintViolationException * @return FebsResponse */ @ExceptionHandler(value = ConstraintViolationException.class) @ResponseStatus(HttpStatus.BAD_REQUEST) public Response handleConstraintViolationException(ConstraintViolationException e) { StringBuilder message = new StringBuilder(); Set> violations = e.getConstraintViolations(); for (ConstraintViolation violation : violations) { Path path = violation.getPropertyPath(); String[] pathArr = StringUtils.splitByWholeSeparatorPreserveAllTokens(path.toString(), "."); message.append(pathArr[1]).append(violation.getMessage()).append(","); } message = new StringBuilder(message.substring(0, message.length() - 1)); return new Response().message(message.toString()); } @ExceptionHandler(value = UnauthorizedException.class) @ResponseStatus(HttpStatus.FORBIDDEN) public void handleUnauthorizedException(Exception e) { log.error("权限不足,{}", e.getMessage()); } } ================================================ FILE: 62.Spring-Boot-Shiro-JWT/src/main/java/com/example/demo/properties/SystemProperties.java ================================================ package com.example.demo.properties; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Configuration; /** * * @author MrBird */ @ConfigurationProperties(prefix = "system") public class SystemProperties { /** * 免认证 URL */ private String anonUrl; /** * token默认有效时间 1天 */ private Long jwtTimeOut = 86400L; public String getAnonUrl() { return anonUrl; } public void setAnonUrl(String anonUrl) { this.anonUrl = anonUrl; } public Long getJwtTimeOut() { return jwtTimeOut; } public void setJwtTimeOut(Long jwtTimeOut) { this.jwtTimeOut = jwtTimeOut; } } ================================================ FILE: 62.Spring-Boot-Shiro-JWT/src/main/java/com/example/demo/runner/PrintRunner.java ================================================ package com.example.demo.runner; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.stereotype.Component; /** * @author MrBird */ @Component public class PrintRunner implements ApplicationRunner { private Logger logger = LoggerFactory.getLogger(this.getClass()); @Override public void run(ApplicationArguments args) { logger.info("Provided by handsome 帅比裙主,详情见readme.md"); } } ================================================ FILE: 62.Spring-Boot-Shiro-JWT/src/main/java/com/example/demo/utils/DateUtil.java ================================================ package com.example.demo.utils; import java.text.ParseException; import java.text.SimpleDateFormat; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.Date; import java.util.Locale; /** * 时间工具类 * * @author MrBird */ public class DateUtil { public static final String FULL_TIME_PATTERN = "yyyyMMddHHmmss"; public static final String FULL_TIME_SPLIT_PATTERN = "yyyy-MM-dd HH:mm:ss"; public static String formatFullTime(LocalDateTime localDateTime) { return formatFullTime(localDateTime, FULL_TIME_PATTERN); } public static String formatFullTime(LocalDateTime localDateTime, String pattern) { DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern); return localDateTime.format(dateTimeFormatter); } private static String getDateFormat(Date date, String dateFormatType) { SimpleDateFormat simformat = new SimpleDateFormat(dateFormatType); return simformat.format(date); } public static String formatCSTTime(String date, String format) throws ParseException { SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.US); Date d = sdf.parse(date); return DateUtil.getDateFormat(d, format); } } ================================================ FILE: 62.Spring-Boot-Shiro-JWT/src/main/java/com/example/demo/utils/MD5Util.java ================================================ package com.example.demo.utils; import org.apache.shiro.crypto.hash.SimpleHash; import org.apache.shiro.util.ByteSource; /** * * @author MrBird */ public class MD5Util { protected MD5Util(){ } private static final String ALGORITH_NAME = "md5"; private static final int HASH_ITERATIONS = 2; public static String encrypt(String password) { return new SimpleHash(ALGORITH_NAME, password, ByteSource.Util.bytes(password), HASH_ITERATIONS).toHex(); } public static String encrypt(String username, String password) { return new SimpleHash(ALGORITH_NAME, password, ByteSource.Util.bytes(username.toLowerCase() + password), HASH_ITERATIONS).toHex(); } public static void main(String[] args) { System.out.println(encrypt("scott","123456")); } } ================================================ FILE: 62.Spring-Boot-Shiro-JWT/src/main/java/com/example/demo/utils/SpringContextUtil.java ================================================ package com.example.demo.utils; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; /** * Spring Context 工具类 * * @author MrBird * */ @Component public class SpringContextUtil implements ApplicationContextAware { private static ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { SpringContextUtil.applicationContext = applicationContext; } public static Object getBean(String name) { return applicationContext.getBean(name); } public static T getBean(Class clazz){ return applicationContext.getBean(clazz); } public static T getBean(String name, Class requiredType) { return applicationContext.getBean(name, requiredType); } public static boolean containsBean(String name) { return applicationContext.containsBean(name); } public static boolean isSingleton(String name) { return applicationContext.isSingleton(name); } public static Class getType(String name) { return applicationContext.getType(name); } } ================================================ FILE: 62.Spring-Boot-Shiro-JWT/src/main/java/com/example/demo/utils/SystemUtils.java ================================================ package com.example.demo.utils; import com.example.demo.domain.User; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.*; /** * 系统工具类 * * @author MrBird */ public class SystemUtils { private static Logger log = LoggerFactory.getLogger(SystemUtils.class); /** * 模拟两个用户 * * @return List */ private static List users() { List users = new ArrayList<>(); // 模拟两个用户: // 1. 用户名 admin,密码 123456,角色 admin(管理员),权限 "user:add","user:view" // 1. 用户名 scott,密码 123456,角色 regist(注册用户),权限 "user:view" users.add(new User( "admin", "bfc62b3f67a4c3e57df84dad8cc48a3b", new HashSet<>(Collections.singletonList("admin")), new HashSet<>(Arrays.asList("user:add", "user:view")))); users.add(new User( "scott", "11bd73355c7bbbac151e4e4f943e59be", new HashSet<>(Collections.singletonList("regist")), new HashSet<>(Collections.singletonList("user:view")))); return users; } /** * 获取用户 * * @param username 用户名 * @return 用户 */ public static User getUser(String username) { List users = SystemUtils.users(); return users.stream().filter(user -> StringUtils.equalsIgnoreCase(username, user.getUsername())).findFirst().orElse(null); } } ================================================ FILE: 62.Spring-Boot-Shiro-JWT/src/main/resources/ValidationMessages.properties ================================================ required=\u4E0D\u80FD\u4E3A\u7A7A ================================================ FILE: 62.Spring-Boot-Shiro-JWT/src/main/resources/application.yml ================================================ system: # 后端免认证接口 url anonUrl: /login # token有效期,单位秒 jwtTimeOut: 3600 spring: aop: proxy-target-class: true ================================================ FILE: 62.Spring-Boot-Shiro-JWT/src/main/resources/postman.json ================================================ { "info": { "_postman_id": "37b4020a-9a03-4d5a-9504-9f6520a040f1", "name": "测试请求", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" }, "item": [ { "name": "登录测试", "event": [ { "listen": "prerequest", "script": { "id": "465a0661-a8b5-4ddd-ad37-6a92f9a25348", "exec": [ "" ], "type": "text/javascript" } } ], "request": { "method": "POST", "header": [ { "key": "Content-Type", "name": "Content-Type", "type": "text", "value": "text/properties" } ], "body": { "mode": "raw", "raw": "" }, "url": { "raw": "localhost:8080/login?username=admin&password=123456", "host": [ "localhost" ], "port": "8080", "path": [ "login" ], "query": [ { "key": "username", "value": "admin" }, { "key": "password", "value": "123456" } ] } }, "response": [] }, { "name": "admin请求测试", "request": { "method": "GET", "header": [ { "key": "Token", "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1NTE3MDIyNTgsInVzZXJuYW1lIjoiYWRtaW4ifQ.EyruxB9m6VJ2Rs_29iB1IblKD1H2fVTB2Nb0xQ4PYOc", "type": "text" } ], "body": { "mode": "raw", "raw": "" }, "url": { "raw": "localhost:8080/test/2", "host": [ "localhost" ], "port": "8080", "path": [ "test", "2" ] } }, "response": [] }, { "name": "scott请求测试", "request": { "method": "GET", "header": [ { "key": "Token", "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1NTE3MDIxODMsInVzZXJuYW1lIjoic2NvdHQifQ._rR8kgvYPsnnZwMW6QdaSD8jw8clcWI0b0atd3oEdGY", "equals": true } ], "body": { "mode": "raw", "raw": "" }, "url": { "raw": "localhost:8080/test/3?Token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1NTE3MDIxODMsInVzZXJuYW1lIjoic2NvdHQifQ._rR8kgvYPsnnZwMW6QdaSD8jw8clcWI0b0atd3oEdGY", "host": [ "localhost" ], "port": "8080", "path": [ "test", "3" ], "query": [ { "key": "Token", "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1NTE3MDIxODMsInVzZXJuYW1lIjoic2NvdHQifQ._rR8kgvYPsnnZwMW6QdaSD8jw8clcWI0b0atd3oEdGY" } ] } }, "response": [] }, { "name": "测试/test/1", "request": { "method": "GET", "header": [ { "key": "Token", "value": "", "type": "text" } ], "body": { "mode": "raw", "raw": "" }, "url": { "raw": "localhost:8080/test/1", "host": [ "localhost" ], "port": "8080", "path": [ "test", "1" ] } }, "response": [] } ] } ================================================ FILE: 62.Spring-Boot-Shiro-JWT/src/main/resources/readme.md ================================================ springboot & shiro & jwt 简单demo 这是一个springboot+shiro+jwt的简单demo,无数据库无redis。 系统内置模拟了两个用户: | 用户名 | 密码 | 角色 | 权限 | | :----- | :----- | :---- |:---- | admin | 123456 | admin | "user:add","user:view" | scott | 123456 | regist | "user:view" 参加 com.example.demo.utils.SystemUtils#users 测试样例使用postman导入resources/postman.json即可。 ================================================ FILE: 63.Spring-Security-OAuth2-Guide/pom.xml ================================================ 4.0.0 org.springframework.boot spring-boot-starter-parent 2.1.6.RELEASE cc.mrbird security 0.0.1-SNAPSHOT security Demo project for Spring Boot 1.8 Greenwich.SR1 org.springframework.boot spring-boot-starter-web org.springframework.cloud spring-cloud-starter org.springframework.cloud spring-cloud-starter-oauth2 org.springframework.cloud spring-cloud-starter-security org.apache.commons commons-lang3 org.springframework.cloud spring-cloud-dependencies ${spring-cloud.version} pom import org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 63.Spring-Security-OAuth2-Guide/src/main/java/cc/mrbird/security/SecurityApplication.java ================================================ package cc.mrbird.security; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class SecurityApplication { public static void main(String[] args) { SpringApplication.run(SecurityApplication.class, args); } } ================================================ FILE: 63.Spring-Security-OAuth2-Guide/src/main/java/cc/mrbird/security/config/AuthorizationServerConfig.java ================================================ package cc.mrbird.security.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer; /** * @author MrBird */ @Configuration @EnableAuthorizationServer public class AuthorizationServerConfig extends WebSecurityConfigurerAdapter { @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } } ================================================ FILE: 63.Spring-Security-OAuth2-Guide/src/main/java/cc/mrbird/security/config/ResourceServerConfig.java ================================================ package cc.mrbird.security.config; import org.springframework.context.annotation.Configuration; import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; /** * @author MrBird */ @Configuration @EnableResourceServer public class ResourceServerConfig { } ================================================ FILE: 63.Spring-Security-OAuth2-Guide/src/main/java/cc/mrbird/security/controller/UserController.java ================================================ package cc.mrbird.security.controller; import org.springframework.security.core.Authentication; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; /** * @author MrBird */ @RestController public class UserController { @GetMapping("index") public Object index(Authentication authentication){ return authentication; } } ================================================ FILE: 63.Spring-Security-OAuth2-Guide/src/main/java/cc/mrbird/security/domain/MyUser.java ================================================ package cc.mrbird.security.domain; import java.io.Serializable; public class MyUser implements Serializable { private static final long serialVersionUID = 3497935890426858541L; private String userName; private String password; private boolean accountNonExpired = true; private boolean accountNonLocked= true; private boolean credentialsNonExpired= true; private boolean enabled= true; public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public boolean isAccountNonExpired() { return accountNonExpired; } public void setAccountNonExpired(boolean accountNonExpired) { this.accountNonExpired = accountNonExpired; } public boolean isAccountNonLocked() { return accountNonLocked; } public void setAccountNonLocked(boolean accountNonLocked) { this.accountNonLocked = accountNonLocked; } public boolean isCredentialsNonExpired() { return credentialsNonExpired; } public void setCredentialsNonExpired(boolean credentialsNonExpired) { this.credentialsNonExpired = credentialsNonExpired; } public boolean isEnabled() { return enabled; } public void setEnabled(boolean enabled) { this.enabled = enabled; } } ================================================ FILE: 63.Spring-Security-OAuth2-Guide/src/main/java/cc/mrbird/security/service/UserDetailService.java ================================================ package cc.mrbird.security.service; import cc.mrbird.security.domain.MyUser; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; @Service public class UserDetailService implements UserDetailsService { @Autowired private PasswordEncoder passwordEncoder; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { MyUser user = new MyUser(); user.setUserName(username); user.setPassword(this.passwordEncoder.encode("123456")); return new User(username, user.getPassword(), user.isEnabled(), user.isAccountNonExpired(), user.isCredentialsNonExpired(), user.isAccountNonLocked(), AuthorityUtils.commaSeparatedStringToAuthorityList("admin")); } } ================================================ FILE: 63.Spring-Security-OAuth2-Guide/src/main/resources/application.yml ================================================ security: oauth2: client: client-id: test client-secret: test1234 registered-redirect-uri: http://mrbird.cc ================================================ FILE: 64.Spring-Security-OAuth2-Customize/pom.xml ================================================ 4.0.0 org.springframework.boot spring-boot-starter-parent 2.1.6.RELEASE cc.mrbird security 0.0.1-SNAPSHOT security Demo project for Spring Boot 1.8 Greenwich.SR1 org.springframework.boot spring-boot-starter-web org.springframework.cloud spring-cloud-starter org.springframework.cloud spring-cloud-starter-oauth2 org.springframework.cloud spring-cloud-starter-security org.apache.commons commons-lang3 org.springframework.boot spring-boot-starter-data-redis org.springframework.cloud spring-cloud-dependencies ${spring-cloud.version} pom import org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 64.Spring-Security-OAuth2-Customize/src/main/java/cc/mrbird/security/SecurityApplication.java ================================================ package cc.mrbird.security; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class SecurityApplication { public static void main(String[] args) { SpringApplication.run(SecurityApplication.class, args); } } ================================================ FILE: 64.Spring-Security-OAuth2-Customize/src/main/java/cc/mrbird/security/config/AuthorizationServerConfig.java ================================================ package cc.mrbird.security.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer; /** * @author MrBird */ @Configuration @EnableAuthorizationServer public class AuthorizationServerConfig { @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } } ================================================ FILE: 64.Spring-Security-OAuth2-Customize/src/main/java/cc/mrbird/security/config/ResourceServerConfig.java ================================================ package cc.mrbird.security.config; import cc.mrbird.security.handler.MyAuthenticationFailureHandler; import cc.mrbird.security.handler.MyAuthenticationSucessHandler; import cc.mrbird.security.validate.smscode.SmsAuthenticationConfig; import cc.mrbird.security.validate.smscode.SmsCodeFilter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; /** * @author MrBird */ @Configuration @EnableResourceServer public class ResourceServerConfig extends ResourceServerConfigurerAdapter { @Autowired private MyAuthenticationSucessHandler authenticationSucessHandler; @Autowired private MyAuthenticationFailureHandler authenticationFailureHandler; @Autowired private SmsCodeFilter smsCodeFilter; @Autowired private SmsAuthenticationConfig smsAuthenticationConfig; @Override public void configure(HttpSecurity http) throws Exception { http.addFilterBefore(smsCodeFilter, UsernamePasswordAuthenticationFilter.class) // 添加短信验证码校验过滤器 .formLogin() // 表单登录 .loginProcessingUrl("/login") // 处理表单登录 URL .successHandler(authenticationSucessHandler) // 处理登录成功 .failureHandler(authenticationFailureHandler) // 处理登录失败 .and() .authorizeRequests() // 授权配置 .antMatchers("/code/sms").permitAll() .anyRequest() // 所有请求 .authenticated() // 都需要认证 .and() .csrf().disable() .apply(smsAuthenticationConfig); } } ================================================ FILE: 64.Spring-Security-OAuth2-Customize/src/main/java/cc/mrbird/security/controller/UserController.java ================================================ package cc.mrbird.security.controller; import org.springframework.security.core.Authentication; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; /** * @author MrBird */ @RestController public class UserController { @GetMapping("index") public Object index(@AuthenticationPrincipal Authentication authentication){ return authentication; } } ================================================ FILE: 64.Spring-Security-OAuth2-Customize/src/main/java/cc/mrbird/security/controller/ValidateController.java ================================================ package cc.mrbird.security.controller; import cc.mrbird.security.service.RedisCodeService; import cc.mrbird.security.validate.smscode.SmsCode; import org.apache.commons.lang3.RandomStringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.context.request.ServletWebRequest; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @RestController public class ValidateController { @Autowired private RedisCodeService redisCodeService; @GetMapping("/code/sms") public void createSmsCode(HttpServletRequest request, HttpServletResponse response, String mobile) throws Exception { SmsCode smsCode = createSMSCode(); redisCodeService.save(smsCode, new ServletWebRequest(request), mobile); // 输出验证码到控制台代替短信发送服务 System.out.println("手机号" + mobile + "的登录验证码为:" + smsCode.getCode() + ",有效时间为120秒"); } private SmsCode createSMSCode() { String code = RandomStringUtils.randomNumeric(6); return new SmsCode(code); } } ================================================ FILE: 64.Spring-Security-OAuth2-Customize/src/main/java/cc/mrbird/security/domain/MyUser.java ================================================ package cc.mrbird.security.domain; import java.io.Serializable; public class MyUser implements Serializable { private static final long serialVersionUID = 3497935890426858541L; private String userName; private String password; private boolean accountNonExpired = true; private boolean accountNonLocked= true; private boolean credentialsNonExpired= true; private boolean enabled= true; public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public boolean isAccountNonExpired() { return accountNonExpired; } public void setAccountNonExpired(boolean accountNonExpired) { this.accountNonExpired = accountNonExpired; } public boolean isAccountNonLocked() { return accountNonLocked; } public void setAccountNonLocked(boolean accountNonLocked) { this.accountNonLocked = accountNonLocked; } public boolean isCredentialsNonExpired() { return credentialsNonExpired; } public void setCredentialsNonExpired(boolean credentialsNonExpired) { this.credentialsNonExpired = credentialsNonExpired; } public boolean isEnabled() { return enabled; } public void setEnabled(boolean enabled) { this.enabled = enabled; } } ================================================ FILE: 64.Spring-Security-OAuth2-Customize/src/main/java/cc/mrbird/security/handler/MyAuthenticationFailureHandler.java ================================================ package cc.mrbird.security.handler; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @Component public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler { @Autowired private ObjectMapper mapper; @Override public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException { response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value()); response.setContentType("application/json;charset=utf-8"); response.getWriter().write(mapper.writeValueAsString(exception.getMessage())); } } ================================================ FILE: 64.Spring-Security-OAuth2-Customize/src/main/java/cc/mrbird/security/handler/MyAuthenticationSucessHandler.java ================================================ package cc.mrbird.security.handler; import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.core.Authentication; import org.springframework.security.oauth2.common.OAuth2AccessToken; import org.springframework.security.oauth2.common.exceptions.UnapprovedClientAuthenticationException; import org.springframework.security.oauth2.provider.*; import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices; import org.springframework.security.web.authentication.AuthenticationSuccessHandler; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.Base64; import java.util.HashMap; @Component public class MyAuthenticationSucessHandler implements AuthenticationSuccessHandler { private Logger log = LoggerFactory.getLogger(this.getClass()); @Autowired private ClientDetailsService clientDetailsService; @Autowired private AuthorizationServerTokenServices authorizationServerTokenServices; @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException { // 1. 从请求头中获取 ClientId String header = request.getHeader("Authorization"); if (header == null || !header.startsWith("Basic ")) { throw new UnapprovedClientAuthenticationException("请求头中无client信息"); } String[] tokens = this.extractAndDecodeHeader(header, request); String clientId = tokens[0]; String clientSecret = tokens[1]; TokenRequest tokenRequest = null; // 2. 通过 ClientDetailsService 获取 ClientDetails ClientDetails clientDetails = clientDetailsService.loadClientByClientId(clientId); // 3. 校验 ClientId和 ClientSecret的正确性 if (clientDetails == null) { throw new UnapprovedClientAuthenticationException("clientId:" + clientId + "对应的信息不存在"); } else if (!StringUtils.equals(clientDetails.getClientSecret(), clientSecret)) { throw new UnapprovedClientAuthenticationException("clientSecret不正确"); } else { // 4. 通过 TokenRequest构造器生成 TokenRequest tokenRequest = new TokenRequest(new HashMap<>(), clientId, clientDetails.getScope(), "custom"); } // 5. 通过 TokenRequest的 createOAuth2Request方法获取 OAuth2Request OAuth2Request oAuth2Request = tokenRequest.createOAuth2Request(clientDetails); // 6. 通过 Authentication和 OAuth2Request构造出 OAuth2Authentication OAuth2Authentication auth2Authentication = new OAuth2Authentication(oAuth2Request, authentication); // 7. 通过 AuthorizationServerTokenServices 生成 OAuth2AccessToken OAuth2AccessToken token = authorizationServerTokenServices.createAccessToken(auth2Authentication); // 8. 返回 Token log.info("登录成功"); response.setContentType("application/json;charset=UTF-8"); response.getWriter().write(new ObjectMapper().writeValueAsString(token)); } private String[] extractAndDecodeHeader(String header, HttpServletRequest request) { byte[] base64Token = header.substring(6).getBytes(StandardCharsets.UTF_8); byte[] decoded; try { decoded = Base64.getDecoder().decode(base64Token); } catch (IllegalArgumentException var7) { throw new BadCredentialsException("Failed to decode basic authentication token"); } String token = new String(decoded, StandardCharsets.UTF_8); int delim = token.indexOf(":"); if (delim == -1) { throw new BadCredentialsException("Invalid basic authentication token"); } else { return new String[]{token.substring(0, delim), token.substring(delim + 1)}; } } } ================================================ FILE: 64.Spring-Security-OAuth2-Customize/src/main/java/cc/mrbird/security/service/RedisCodeService.java ================================================ package cc.mrbird.security.service; import cc.mrbird.security.validate.smscode.SmsCode; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Service; import org.springframework.web.context.request.ServletWebRequest; import java.util.concurrent.TimeUnit; /** * Redis操作验证码服务 */ @Service public class RedisCodeService { private final static String SMS_CODE_PREFIX = "SMS_CODE:"; private final static Integer TIME_OUT = 300; @Autowired private StringRedisTemplate redisTemplate; /** * 保存验证码到 redis * * @param smsCode 短信验证码 * @param request ServletWebRequest */ public void save(SmsCode smsCode, ServletWebRequest request, String mobile) throws Exception { redisTemplate.opsForValue().set(key(request, mobile), smsCode.getCode(), TIME_OUT, TimeUnit.SECONDS); } /** * 获取验证码 * * @param request ServletWebRequest * @return 验证码 */ public String get(ServletWebRequest request, String mobile) throws Exception { return redisTemplate.opsForValue().get(key(request, mobile)); } /** * 移除验证码 * * @param request ServletWebRequest */ public void remove(ServletWebRequest request, String mobile) throws Exception { redisTemplate.delete(key(request, mobile)); } private String key(ServletWebRequest request, String mobile) throws Exception { String deviceId = request.getHeader("deviceId"); if (StringUtils.isBlank(deviceId)) { throw new Exception("请在请求头中设置deviceId"); } return SMS_CODE_PREFIX + deviceId + ":" + mobile; } } ================================================ FILE: 64.Spring-Security-OAuth2-Customize/src/main/java/cc/mrbird/security/service/UserDetailService.java ================================================ package cc.mrbird.security.service; import cc.mrbird.security.domain.MyUser; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.crypto.password.PasswordEncoder; import java.util.ArrayList; import java.util.List; @Configuration public class UserDetailService implements UserDetailsService { @Autowired private PasswordEncoder passwordEncoder; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { // 模拟一个用户,替代数据库获取逻辑 MyUser user = new MyUser(); user.setUserName(username); user.setPassword(this.passwordEncoder.encode("123456")); // 输出加密后的密码 System.out.println(user.getPassword()); List authorities = new ArrayList<>(); if (StringUtils.equalsIgnoreCase("mrbird", username)) { authorities = AuthorityUtils.commaSeparatedStringToAuthorityList("admin"); } else { authorities = AuthorityUtils.commaSeparatedStringToAuthorityList("test"); } return new User(username, user.getPassword(), user.isEnabled(), user.isAccountNonExpired(), user.isCredentialsNonExpired(), user.isAccountNonLocked(), authorities); } } ================================================ FILE: 64.Spring-Security-OAuth2-Customize/src/main/java/cc/mrbird/security/validate/smscode/SmsAuthenticationConfig.java ================================================ package cc.mrbird.security.validate.smscode; import cc.mrbird.security.service.UserDetailService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.SecurityConfigurerAdapter; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.web.DefaultSecurityFilterChain; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.security.web.authentication.AuthenticationSuccessHandler; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.stereotype.Component; @Component public class SmsAuthenticationConfig extends SecurityConfigurerAdapter { @Autowired private AuthenticationSuccessHandler authenticationSuccessHandler; @Autowired private AuthenticationFailureHandler authenticationFailureHandler; @Autowired private UserDetailService userDetailService; @Override public void configure(HttpSecurity http) { SmsAuthenticationFilter smsAuthenticationFilter = new SmsAuthenticationFilter(); smsAuthenticationFilter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class)); smsAuthenticationFilter.setAuthenticationSuccessHandler(authenticationSuccessHandler); smsAuthenticationFilter.setAuthenticationFailureHandler(authenticationFailureHandler); SmsAuthenticationProvider smsAuthenticationProvider = new SmsAuthenticationProvider(); smsAuthenticationProvider.setUserDetailService(userDetailService); http.authenticationProvider(smsAuthenticationProvider) .addFilterAfter(smsAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); } } ================================================ FILE: 64.Spring-Security-OAuth2-Customize/src/main/java/cc/mrbird/security/validate/smscode/SmsAuthenticationFilter.java ================================================ package cc.mrbird.security.validate.smscode; import org.springframework.security.authentication.AuthenticationServiceException; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.util.Assert; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class SmsAuthenticationFilter extends AbstractAuthenticationProcessingFilter { public static final String MOBILE_KEY = "mobile"; private String mobileParameter = MOBILE_KEY; private boolean postOnly = true; public SmsAuthenticationFilter() { super(new AntPathRequestMatcher("/login/mobile", "POST")); } public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { if (postOnly && !request.getMethod().equals("POST")) { throw new AuthenticationServiceException( "Authentication method not supported: " + request.getMethod()); } String mobile = obtainMobile(request); if (mobile == null) { mobile = ""; } mobile = mobile.trim(); SmsAuthenticationToken authRequest = new SmsAuthenticationToken(mobile); setDetails(request, authRequest); return this.getAuthenticationManager().authenticate(authRequest); } protected String obtainMobile(HttpServletRequest request) { return request.getParameter(mobileParameter); } protected void setDetails(HttpServletRequest request, SmsAuthenticationToken authRequest) { authRequest.setDetails(authenticationDetailsSource.buildDetails(request)); } public void setMobileParameter(String mobileParameter) { Assert.hasText(mobileParameter, "mobile parameter must not be empty or null"); this.mobileParameter = mobileParameter; } public void setPostOnly(boolean postOnly) { this.postOnly = postOnly; } public final String getMobileParameter() { return mobileParameter; } } ================================================ FILE: 64.Spring-Security-OAuth2-Customize/src/main/java/cc/mrbird/security/validate/smscode/SmsAuthenticationProvider.java ================================================ package cc.mrbird.security.validate.smscode; import cc.mrbird.security.service.UserDetailService; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.InternalAuthenticationServiceException; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.userdetails.UserDetails; public class SmsAuthenticationProvider implements AuthenticationProvider { private UserDetailService userDetailService; @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { SmsAuthenticationToken authenticationToken = (SmsAuthenticationToken) authentication; UserDetails userDetails = userDetailService.loadUserByUsername((String) authenticationToken.getPrincipal()); if (userDetails == null) throw new InternalAuthenticationServiceException("未找到与该手机号对应的用户"); SmsAuthenticationToken authenticationResult = new SmsAuthenticationToken(userDetails, userDetails.getAuthorities()); authenticationResult.setDetails(authenticationToken.getDetails()); return authenticationResult; } @Override public boolean supports(Class aClass) { return SmsAuthenticationToken.class.isAssignableFrom(aClass); } public UserDetailService getUserDetailService() { return userDetailService; } public void setUserDetailService(UserDetailService userDetailService) { this.userDetailService = userDetailService; } } ================================================ FILE: 64.Spring-Security-OAuth2-Customize/src/main/java/cc/mrbird/security/validate/smscode/SmsAuthenticationToken.java ================================================ package cc.mrbird.security.validate.smscode; import org.springframework.security.authentication.AbstractAuthenticationToken; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.SpringSecurityCoreVersion; import java.util.Collection; public class SmsAuthenticationToken extends AbstractAuthenticationToken { private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID; private final Object principal; public SmsAuthenticationToken(String mobile) { super(null); this.principal = mobile; setAuthenticated(false); } public SmsAuthenticationToken(Object principal, Collection authorities) { super(authorities); this.principal = principal; super.setAuthenticated(true); // must use super, as we override } @Override public Object getCredentials() { return null; } public Object getPrincipal() { return this.principal; } public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException { if (isAuthenticated) { throw new IllegalArgumentException( "Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead"); } super.setAuthenticated(false); } @Override public void eraseCredentials() { super.eraseCredentials(); } } ================================================ FILE: 64.Spring-Security-OAuth2-Customize/src/main/java/cc/mrbird/security/validate/smscode/SmsCode.java ================================================ package cc.mrbird.security.validate.smscode; public class SmsCode { private String code; public SmsCode(String code) { this.code = code; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } } ================================================ FILE: 64.Spring-Security-OAuth2-Customize/src/main/java/cc/mrbird/security/validate/smscode/SmsCodeFilter.java ================================================ package cc.mrbird.security.validate.smscode; import cc.mrbird.security.service.RedisCodeService; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.AuthenticationServiceException; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.stereotype.Component; import org.springframework.web.bind.ServletRequestUtils; import org.springframework.web.context.request.ServletWebRequest; import org.springframework.web.filter.OncePerRequestFilter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @Component public class SmsCodeFilter extends OncePerRequestFilter { @Autowired private AuthenticationFailureHandler authenticationFailureHandler; @Autowired private RedisCodeService redisCodeService; @Override protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException { if (StringUtils.equalsIgnoreCase("/login/mobile", httpServletRequest.getRequestURI()) && StringUtils.equalsIgnoreCase(httpServletRequest.getMethod(), "post")) { try { validateCode(new ServletWebRequest(httpServletRequest)); } catch (Exception e) { authenticationFailureHandler.onAuthenticationFailure(httpServletRequest, httpServletResponse, new AuthenticationServiceException(e.getMessage())); return; } } filterChain.doFilter(httpServletRequest, httpServletResponse); } private void validateCode(ServletWebRequest servletWebRequest) throws Exception { String smsCodeInRequest = ServletRequestUtils.getStringParameter(servletWebRequest.getRequest(), "smsCode"); String mobileInRequest = ServletRequestUtils.getStringParameter(servletWebRequest.getRequest(), "mobile"); String codeInRedis = redisCodeService.get(servletWebRequest, mobileInRequest); if (StringUtils.isBlank(smsCodeInRequest)) { throw new Exception("验证码不能为空!"); } if (codeInRedis == null) { throw new Exception("验证码已过期!"); } if (!StringUtils.equalsIgnoreCase(codeInRedis, smsCodeInRequest)) { throw new Exception("验证码不正确!"); } redisCodeService.remove(servletWebRequest, mobileInRequest); } } ================================================ FILE: 64.Spring-Security-OAuth2-Customize/src/main/resources/application.yml ================================================ security: oauth2: client: client-id: test client-secret: test1234 ================================================ FILE: 65.Spring-Security-OAuth2-Config/pom.xml ================================================ 4.0.0 org.springframework.boot spring-boot-starter-parent 2.1.6.RELEASE cc.mrbird security 0.0.1-SNAPSHOT security Demo project for Spring Boot 1.8 Greenwich.SR1 org.springframework.boot spring-boot-starter-web org.springframework.cloud spring-cloud-starter org.springframework.cloud spring-cloud-starter-oauth2 org.springframework.cloud spring-cloud-starter-security org.apache.commons commons-lang3 org.springframework.boot spring-boot-starter-data-redis io.jsonwebtoken jjwt 0.9.1 org.springframework.cloud spring-cloud-dependencies ${spring-cloud.version} pom import org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 65.Spring-Security-OAuth2-Config/security.postman_collection.json ================================================ { "info": { "_postman_id": "3e982fc6-c1cb-4459-bca3-5fa81b956a37", "name": "security", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" }, "item": [ { "name": "/oauth/token 密码模式", "request": { "auth": { "type": "noauth" }, "method": "POST", "header": [ { "warning": "This is a duplicate header and will be overridden by the Authorization header generated by Postman.", "key": "Authorization", "value": "Basic dGVzdDE6dGVzdDExMTE=", "type": "text" } ], "url": { "raw": "localhost:8080/oauth/token?grant_type=password&username=mrbird&password=123456&scope=all", "host": [ "localhost" ], "port": "8080", "path": [ "oauth", "token" ], "query": [ { "key": "grant_type", "value": "password" }, { "key": "username", "value": "mrbird" }, { "key": "password", "value": "123456" }, { "key": "scope", "value": "all" } ] } }, "response": [] }, { "name": "/oauth/token 授权码模式", "request": { "auth": { "type": "noauth" }, "method": "POST", "header": [ { "key": "Authorization", "type": "text", "value": "Basic dGVzdDE6dGVzdDExMTE=", "warning": "This is a duplicate header and will be overridden by the Authorization header generated by Postman." } ], "url": { "raw": "localhost:8080/oauth/token?grant_type=authorization_code&code=1qcUlU&client_id=test&redirect_uri=http://mrbird.cc&scope=all", "host": [ "localhost" ], "port": "8080", "path": [ "oauth", "token" ], "query": [ { "key": "grant_type", "value": "authorization_code" }, { "key": "code", "value": "1qcUlU" }, { "key": "client_id", "value": "test" }, { "key": "redirect_uri", "value": "http://mrbird.cc" }, { "key": "scope", "value": "all" } ] } }, "response": [] }, { "name": "/oauth/token 刷新令牌", "request": { "auth": { "type": "noauth" }, "method": "POST", "header": [ { "key": "Authorization", "value": "dGVzdDE6dGVzdDExMTE=", "type": "text" } ], "url": { "raw": "localhost:8080/oauth/token?grant_type=refresh_token&refresh_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJtcmJpcmQiLCJzY29wZSI6W10sImF0aSI6IjQ1NmNlZDZjLTgzMTYtNDgyNy1iY2EwLWU4ZjVlMzkyYTcyZCIsImV4cCI6MTU2MjQwMTUzMywibWVzc2FnZSI6ImhlbGxvIHdvcmxkIiwiYXV0aG9yaXRpZXMiOlsiYWRtaW4iXSwianRpIjoiNGYyOTAxMTItZDllYi00ZjQ5LTk0ZDctZmE3ODRlNmEyYWI1IiwiY2xpZW50X2lkIjoidGVzdDEifQ.5ldS0Fn4znrnW7vAAuy1RVKjvV3H01b42om3-uyNz50", "host": [ "localhost" ], "port": "8080", "path": [ "oauth", "token" ], "query": [ { "key": "grant_type", "value": "refresh_token" }, { "key": "refresh_token", "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJtcmJpcmQiLCJzY29wZSI6W10sImF0aSI6IjQ1NmNlZDZjLTgzMTYtNDgyNy1iY2EwLWU4ZjVlMzkyYTcyZCIsImV4cCI6MTU2MjQwMTUzMywibWVzc2FnZSI6ImhlbGxvIHdvcmxkIiwiYXV0aG9yaXRpZXMiOlsiYWRtaW4iXSwianRpIjoiNGYyOTAxMTItZDllYi00ZjQ5LTk0ZDctZmE3ODRlNmEyYWI1IiwiY2xpZW50X2lkIjoidGVzdDEifQ.5ldS0Fn4znrnW7vAAuy1RVKjvV3H01b42om3-uyNz50" }, { "key": "client_id", "value": "test1", "disabled": true }, { "key": "client_secret", "value": "test1111", "disabled": true } ] } }, "response": [] }, { "name": "/index", "request": { "method": "GET", "header": [ { "key": "Authorization", "value": "bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NjE1NTc2MjEsInVzZXJfbmFtZSI6Im1yYmlyZCIsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6ImRiYzc2NjE4LTEyMzQtNDI4My1iN2E5LWRiNjE0MGJkOWY0NCIsImNsaWVudF9pZCI6InRlc3QxIiwic2NvcGUiOlsiYWxsIl19.jpV34FhG0bkry2BY0JS8Jga7XOZ8UbBWDZ-ROoHc5ps", "type": "text" } ], "url": { "raw": "localhost:8080/index", "host": [ "localhost" ], "port": "8080", "path": [ "index" ] } }, "response": [] }, { "name": "/login 自定义登录获取令牌(用户名密码)", "request": { "method": "POST", "header": [ { "key": "Authorization", "type": "text", "value": "Basic dGVzdDE6dGVzdDExMTE=" }, { "key": "Content-Type", "type": "text", "value": "", "disabled": true } ], "url": { "raw": "localhost:8080/login?username=mrbird&password=123456", "host": [ "localhost" ], "port": "8080", "path": [ "login" ], "query": [ { "key": "username", "value": "mrbird" }, { "key": "password", "value": "123456" } ] } }, "response": [] }, { "name": "/code/sms", "request": { "method": "GET", "header": [ { "key": "deviceId", "value": "xxooxx", "type": "text" } ], "url": { "raw": "localhost:8080/code/sms?mobile=17720202020", "host": [ "localhost" ], "port": "8080", "path": [ "code", "sms" ], "query": [ { "key": "mobile", "value": "17720202020" } ] } }, "response": [] }, { "name": "/login/mobile 手机验证码获取令牌", "request": { "method": "POST", "header": [ { "key": "Authorization", "value": "Basic dGVzdDp0ZXN0MTIzNA==", "type": "text" }, { "key": "deviceId", "value": "xxooxx", "type": "text" } ], "url": { "raw": "localhost:8080/login/mobile?mobile=17720202020&smsCode=486498", "host": [ "localhost" ], "port": "8080", "path": [ "login", "mobile" ], "query": [ { "key": "mobile", "value": "17720202020" }, { "key": "smsCode", "value": "486498" } ] } }, "response": [] } ] } ================================================ FILE: 65.Spring-Security-OAuth2-Config/src/main/java/cc/mrbird/security/SecurityApplication.java ================================================ package cc.mrbird.security; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class SecurityApplication { public static void main(String[] args) { SpringApplication.run(SecurityApplication.class, args); } } ================================================ FILE: 65.Spring-Security-OAuth2-Config/src/main/java/cc/mrbird/security/config/AuthorizationServerConfig.java ================================================ package cc.mrbird.security.config; import cc.mrbird.security.service.UserDetailService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer; import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter; import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer; import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer; import org.springframework.security.oauth2.provider.token.TokenEnhancer; import org.springframework.security.oauth2.provider.token.TokenEnhancerChain; import org.springframework.security.oauth2.provider.token.TokenStore; import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; import java.util.ArrayList; import java.util.List; /** * @author MrBird */ @Configuration @EnableAuthorizationServer public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { // @Autowired // private TokenStore redisTokenStore; @Autowired private TokenStore jwtTokenStore; @Autowired private JwtAccessTokenConverter jwtAccessTokenConverter; @Autowired private AuthenticationManager authenticationManager; @Autowired private TokenEnhancer tokenEnhancer; @Autowired private UserDetailService userDetailService; @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) { TokenEnhancerChain enhancerChain = new TokenEnhancerChain(); List enhancers = new ArrayList<>(); enhancers.add(tokenEnhancer); enhancers.add(jwtAccessTokenConverter); enhancerChain.setTokenEnhancers(enhancers); endpoints.authenticationManager(authenticationManager) .tokenStore(jwtTokenStore) .accessTokenConverter(jwtAccessTokenConverter) .userDetailsService(userDetailService); } @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory() .withClient("test1") .secret(new BCryptPasswordEncoder().encode("test1111")) .authorizedGrantTypes("password", "refresh_token") .accessTokenValiditySeconds(3600) .refreshTokenValiditySeconds(864000) .scopes("all", "a", "b", "c") .and() .withClient("test2") .secret(new BCryptPasswordEncoder().encode("test2222")) .accessTokenValiditySeconds(7200); } } ================================================ FILE: 65.Spring-Security-OAuth2-Config/src/main/java/cc/mrbird/security/config/JWTokenConfig.java ================================================ package cc.mrbird.security.config; import cc.mrbird.security.enhancer.JWTokenEnhancer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.oauth2.provider.token.TokenEnhancer; import org.springframework.security.oauth2.provider.token.TokenStore; import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; import org.springframework.security.oauth2.provider.token.store.JwtTokenStore; /** * @author MrBird */ @Configuration public class JWTokenConfig { @Bean public TokenStore jwtTokenStore() { return new JwtTokenStore(jwtAccessTokenConverter()); } @Bean public JwtAccessTokenConverter jwtAccessTokenConverter() { JwtAccessTokenConverter accessTokenConverter = new JwtAccessTokenConverter(); accessTokenConverter.setSigningKey("test_key"); // 签名密钥 return accessTokenConverter; } @Bean public TokenEnhancer tokenEnhancer() { return new JWTokenEnhancer(); } } ================================================ FILE: 65.Spring-Security-OAuth2-Config/src/main/java/cc/mrbird/security/config/ResourceServerConfig.java ================================================ package cc.mrbird.security.config; import cc.mrbird.security.handler.MyAuthenticationFailureHandler; import cc.mrbird.security.handler.MyAuthenticationSucessHandler; import cc.mrbird.security.validate.smscode.SmsAuthenticationConfig; import cc.mrbird.security.validate.smscode.SmsCodeFilter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; /** * @author MrBird */ @Configuration @EnableResourceServer public class ResourceServerConfig extends ResourceServerConfigurerAdapter { @Autowired private MyAuthenticationSucessHandler authenticationSucessHandler; @Autowired private MyAuthenticationFailureHandler authenticationFailureHandler; @Autowired private SmsCodeFilter smsCodeFilter; @Autowired private SmsAuthenticationConfig smsAuthenticationConfig; @Override public void configure(HttpSecurity http) throws Exception { http.addFilterBefore(smsCodeFilter, UsernamePasswordAuthenticationFilter.class) // 添加短信验证码校验过滤器 .formLogin() // 表单登录 .loginProcessingUrl("/login") // 处理表单登录 URL .successHandler(authenticationSucessHandler) // 处理登录成功 .failureHandler(authenticationFailureHandler) // 处理登录失败 .and() .authorizeRequests() // 授权配置 .antMatchers("/code/sms").permitAll() .anyRequest() // 所有请求 .authenticated() // 都需要认证 .and() .csrf().disable() .apply(smsAuthenticationConfig); } } ================================================ FILE: 65.Spring-Security-OAuth2-Config/src/main/java/cc/mrbird/security/config/SecurityConfig.java ================================================ package cc.mrbird.security.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.BeanIds; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; /** * @author MrBird */ @Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { @Bean(name = BeanIds.AUTHENTICATION_MANAGER) @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } } ================================================ FILE: 65.Spring-Security-OAuth2-Config/src/main/java/cc/mrbird/security/config/TokenStoreConfig.java ================================================ package cc.mrbird.security.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.security.oauth2.provider.token.TokenStore; import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore; /** * @author MrBird */ @Configuration public class TokenStoreConfig { @Autowired private RedisConnectionFactory redisConnectionFactory; // @Bean // public TokenStore redisTokenStore(){ // return new RedisTokenStore(redisConnectionFactory); // } } ================================================ FILE: 65.Spring-Security-OAuth2-Config/src/main/java/cc/mrbird/security/controller/UserController.java ================================================ package cc.mrbird.security.controller; import io.jsonwebtoken.Jwts; import org.apache.commons.lang3.StringUtils; import org.springframework.security.core.Authentication; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; import java.nio.charset.StandardCharsets; /** * @author MrBird */ @RestController public class UserController { @GetMapping("index") public Object index(@AuthenticationPrincipal Authentication authentication, HttpServletRequest request) { String header = request.getHeader("Authorization"); String token = StringUtils.substringAfter(header, "bearer "); return Jwts.parser().setSigningKey("test_key".getBytes(StandardCharsets.UTF_8)).parseClaimsJws(token).getBody(); } } ================================================ FILE: 65.Spring-Security-OAuth2-Config/src/main/java/cc/mrbird/security/controller/ValidateController.java ================================================ package cc.mrbird.security.controller; import cc.mrbird.security.service.RedisCodeService; import cc.mrbird.security.validate.smscode.SmsCode; import org.apache.commons.lang3.RandomStringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.context.request.ServletWebRequest; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @RestController public class ValidateController { @Autowired private RedisCodeService redisCodeService; @GetMapping("/code/sms") public void createSmsCode(HttpServletRequest request, HttpServletResponse response, String mobile) throws Exception { SmsCode smsCode = createSMSCode(); redisCodeService.save(smsCode, new ServletWebRequest(request), mobile); // 输出验证码到控制台代替短信发送服务 System.out.println("手机号" + mobile + "的登录验证码为:" + smsCode.getCode() + ",有效时间为120秒"); } private SmsCode createSMSCode() { String code = RandomStringUtils.randomNumeric(6); return new SmsCode(code); } } ================================================ FILE: 65.Spring-Security-OAuth2-Config/src/main/java/cc/mrbird/security/domain/MyUser.java ================================================ package cc.mrbird.security.domain; import java.io.Serializable; public class MyUser implements Serializable { private static final long serialVersionUID = 3497935890426858541L; private String userName; private String password; private boolean accountNonExpired = true; private boolean accountNonLocked= true; private boolean credentialsNonExpired= true; private boolean enabled= true; public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public boolean isAccountNonExpired() { return accountNonExpired; } public void setAccountNonExpired(boolean accountNonExpired) { this.accountNonExpired = accountNonExpired; } public boolean isAccountNonLocked() { return accountNonLocked; } public void setAccountNonLocked(boolean accountNonLocked) { this.accountNonLocked = accountNonLocked; } public boolean isCredentialsNonExpired() { return credentialsNonExpired; } public void setCredentialsNonExpired(boolean credentialsNonExpired) { this.credentialsNonExpired = credentialsNonExpired; } public boolean isEnabled() { return enabled; } public void setEnabled(boolean enabled) { this.enabled = enabled; } } ================================================ FILE: 65.Spring-Security-OAuth2-Config/src/main/java/cc/mrbird/security/enhancer/JWTokenEnhancer.java ================================================ package cc.mrbird.security.enhancer; import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken; import org.springframework.security.oauth2.common.OAuth2AccessToken; import org.springframework.security.oauth2.provider.OAuth2Authentication; import org.springframework.security.oauth2.provider.token.TokenEnhancer; import java.util.HashMap; import java.util.Map; /** * @author MrBird */ public class JWTokenEnhancer implements TokenEnhancer { @Override public OAuth2AccessToken enhance(OAuth2AccessToken oAuth2AccessToken, OAuth2Authentication oAuth2Authentication) { Map info = new HashMap<>(); info.put("message", "hello world"); ((DefaultOAuth2AccessToken) oAuth2AccessToken).setAdditionalInformation(info); return oAuth2AccessToken; } } ================================================ FILE: 65.Spring-Security-OAuth2-Config/src/main/java/cc/mrbird/security/handler/MyAuthenticationFailureHandler.java ================================================ package cc.mrbird.security.handler; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @Component public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler { @Autowired private ObjectMapper mapper; @Override public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException { response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value()); response.setContentType("application/json;charset=utf-8"); response.getWriter().write(mapper.writeValueAsString(exception.getMessage())); } } ================================================ FILE: 65.Spring-Security-OAuth2-Config/src/main/java/cc/mrbird/security/handler/MyAuthenticationSucessHandler.java ================================================ package cc.mrbird.security.handler; import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.core.Authentication; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.oauth2.common.OAuth2AccessToken; import org.springframework.security.oauth2.common.exceptions.UnapprovedClientAuthenticationException; import org.springframework.security.oauth2.provider.*; import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices; import org.springframework.security.web.authentication.AuthenticationSuccessHandler; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.Base64; import java.util.HashMap; @Component public class MyAuthenticationSucessHandler implements AuthenticationSuccessHandler { private Logger log = LoggerFactory.getLogger(this.getClass()); @Autowired private ClientDetailsService clientDetailsService; @Autowired private AuthorizationServerTokenServices authorizationServerTokenServices; @Autowired private PasswordEncoder passwordEncoder; @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException { // 1. 从请求头中获取 ClientId String header = request.getHeader("Authorization"); if (header == null || !header.startsWith("Basic ")) { throw new UnapprovedClientAuthenticationException("请求头中无client信息"); } String[] tokens = this.extractAndDecodeHeader(header, request); String clientId = tokens[0]; String clientSecret = tokens[1]; TokenRequest tokenRequest = null; // 2. 通过 ClientDetailsService 获取 ClientDetails ClientDetails clientDetails = clientDetailsService.loadClientByClientId(clientId); // 3. 校验 ClientId和 ClientSecret的正确性 if (clientDetails == null) { throw new UnapprovedClientAuthenticationException("clientId:" + clientId + "对应的信息不存在"); } else if (!passwordEncoder.matches(clientSecret, clientDetails.getClientSecret())) { throw new UnapprovedClientAuthenticationException("clientSecret不正确"); } else { // 4. 通过 TokenRequest构造器生成 TokenRequest tokenRequest = new TokenRequest(new HashMap<>(), clientId, clientDetails.getScope(), "custom"); } // 5. 通过 TokenRequest的 createOAuth2Request方法获取 OAuth2Request OAuth2Request oAuth2Request = tokenRequest.createOAuth2Request(clientDetails); // 6. 通过 Authentication和 OAuth2Request构造出 OAuth2Authentication OAuth2Authentication auth2Authentication = new OAuth2Authentication(oAuth2Request, authentication); // 7. 通过 AuthorizationServerTokenServices 生成 OAuth2AccessToken OAuth2AccessToken token = authorizationServerTokenServices.createAccessToken(auth2Authentication); // 8. 返回 Token log.info("登录成功"); response.setContentType("application/json;charset=UTF-8"); response.getWriter().write(new ObjectMapper().writeValueAsString(token)); } private String[] extractAndDecodeHeader(String header, HttpServletRequest request) { byte[] base64Token = header.substring(6).getBytes(StandardCharsets.UTF_8); byte[] decoded; try { decoded = Base64.getDecoder().decode(base64Token); } catch (IllegalArgumentException var7) { throw new BadCredentialsException("Failed to decode basic authentication token"); } String token = new String(decoded, StandardCharsets.UTF_8); int delim = token.indexOf(":"); if (delim == -1) { throw new BadCredentialsException("Invalid basic authentication token"); } else { return new String[]{token.substring(0, delim), token.substring(delim + 1)}; } } } ================================================ FILE: 65.Spring-Security-OAuth2-Config/src/main/java/cc/mrbird/security/service/RedisCodeService.java ================================================ package cc.mrbird.security.service; import cc.mrbird.security.validate.smscode.SmsCode; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Service; import org.springframework.web.context.request.ServletWebRequest; import java.util.concurrent.TimeUnit; /** * Redis操作验证码服务 */ @Service public class RedisCodeService { private final static String SMS_CODE_PREFIX = "SMS_CODE:"; private final static Integer TIME_OUT = 300; @Autowired private StringRedisTemplate redisTemplate; /** * 保存验证码到 redis * * @param smsCode 短信验证码 * @param request ServletWebRequest */ public void save(SmsCode smsCode, ServletWebRequest request, String mobile) throws Exception { redisTemplate.opsForValue().set(key(request, mobile), smsCode.getCode(), TIME_OUT, TimeUnit.SECONDS); } /** * 获取验证码 * * @param request ServletWebRequest * @return 验证码 */ public String get(ServletWebRequest request, String mobile) throws Exception { return redisTemplate.opsForValue().get(key(request, mobile)); } /** * 移除验证码 * * @param request ServletWebRequest */ public void remove(ServletWebRequest request, String mobile) throws Exception { redisTemplate.delete(key(request, mobile)); } private String key(ServletWebRequest request, String mobile) throws Exception { String deviceId = request.getHeader("deviceId"); if (StringUtils.isBlank(deviceId)) { throw new Exception("请在请求头中设置deviceId"); } return SMS_CODE_PREFIX + deviceId + ":" + mobile; } } ================================================ FILE: 65.Spring-Security-OAuth2-Config/src/main/java/cc/mrbird/security/service/UserDetailService.java ================================================ package cc.mrbird.security.service; import cc.mrbird.security.domain.MyUser; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.crypto.password.PasswordEncoder; import java.util.ArrayList; import java.util.List; @Configuration public class UserDetailService implements UserDetailsService { @Autowired private PasswordEncoder passwordEncoder; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { // 模拟一个用户,替代数据库获取逻辑 MyUser user = new MyUser(); user.setUserName(username); user.setPassword(this.passwordEncoder.encode("123456")); // 输出加密后的密码 System.out.println(user.getPassword()); List authorities = new ArrayList<>(); if (StringUtils.equalsIgnoreCase("mrbird", username)) { authorities = AuthorityUtils.commaSeparatedStringToAuthorityList("admin"); } else { authorities = AuthorityUtils.commaSeparatedStringToAuthorityList("test"); } return new User(username, user.getPassword(), user.isEnabled(), user.isAccountNonExpired(), user.isCredentialsNonExpired(), user.isAccountNonLocked(), authorities); } } ================================================ FILE: 65.Spring-Security-OAuth2-Config/src/main/java/cc/mrbird/security/validate/smscode/SmsAuthenticationConfig.java ================================================ package cc.mrbird.security.validate.smscode; import cc.mrbird.security.service.UserDetailService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.SecurityConfigurerAdapter; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.web.DefaultSecurityFilterChain; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.security.web.authentication.AuthenticationSuccessHandler; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.stereotype.Component; @Component public class SmsAuthenticationConfig extends SecurityConfigurerAdapter { @Autowired private AuthenticationSuccessHandler authenticationSuccessHandler; @Autowired private AuthenticationFailureHandler authenticationFailureHandler; @Autowired private UserDetailService userDetailService; @Override public void configure(HttpSecurity http) { SmsAuthenticationFilter smsAuthenticationFilter = new SmsAuthenticationFilter(); smsAuthenticationFilter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class)); smsAuthenticationFilter.setAuthenticationSuccessHandler(authenticationSuccessHandler); smsAuthenticationFilter.setAuthenticationFailureHandler(authenticationFailureHandler); SmsAuthenticationProvider smsAuthenticationProvider = new SmsAuthenticationProvider(); smsAuthenticationProvider.setUserDetailService(userDetailService); http.authenticationProvider(smsAuthenticationProvider) .addFilterAfter(smsAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); } } ================================================ FILE: 65.Spring-Security-OAuth2-Config/src/main/java/cc/mrbird/security/validate/smscode/SmsAuthenticationFilter.java ================================================ package cc.mrbird.security.validate.smscode; import org.springframework.security.authentication.AuthenticationServiceException; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.util.Assert; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class SmsAuthenticationFilter extends AbstractAuthenticationProcessingFilter { public static final String MOBILE_KEY = "mobile"; private String mobileParameter = MOBILE_KEY; private boolean postOnly = true; public SmsAuthenticationFilter() { super(new AntPathRequestMatcher("/login/mobile", "POST")); } public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { if (postOnly && !request.getMethod().equals("POST")) { throw new AuthenticationServiceException( "Authentication method not supported: " + request.getMethod()); } String mobile = obtainMobile(request); if (mobile == null) { mobile = ""; } mobile = mobile.trim(); SmsAuthenticationToken authRequest = new SmsAuthenticationToken(mobile); setDetails(request, authRequest); return this.getAuthenticationManager().authenticate(authRequest); } protected String obtainMobile(HttpServletRequest request) { return request.getParameter(mobileParameter); } protected void setDetails(HttpServletRequest request, SmsAuthenticationToken authRequest) { authRequest.setDetails(authenticationDetailsSource.buildDetails(request)); } public void setMobileParameter(String mobileParameter) { Assert.hasText(mobileParameter, "mobile parameter must not be empty or null"); this.mobileParameter = mobileParameter; } public void setPostOnly(boolean postOnly) { this.postOnly = postOnly; } public final String getMobileParameter() { return mobileParameter; } } ================================================ FILE: 65.Spring-Security-OAuth2-Config/src/main/java/cc/mrbird/security/validate/smscode/SmsAuthenticationProvider.java ================================================ package cc.mrbird.security.validate.smscode; import cc.mrbird.security.service.UserDetailService; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.InternalAuthenticationServiceException; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.userdetails.UserDetails; public class SmsAuthenticationProvider implements AuthenticationProvider { private UserDetailService userDetailService; @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { SmsAuthenticationToken authenticationToken = (SmsAuthenticationToken) authentication; UserDetails userDetails = userDetailService.loadUserByUsername((String) authenticationToken.getPrincipal()); if (userDetails == null) throw new InternalAuthenticationServiceException("未找到与该手机号对应的用户"); SmsAuthenticationToken authenticationResult = new SmsAuthenticationToken(userDetails, userDetails.getAuthorities()); authenticationResult.setDetails(authenticationToken.getDetails()); return authenticationResult; } @Override public boolean supports(Class aClass) { return SmsAuthenticationToken.class.isAssignableFrom(aClass); } public UserDetailService getUserDetailService() { return userDetailService; } public void setUserDetailService(UserDetailService userDetailService) { this.userDetailService = userDetailService; } } ================================================ FILE: 65.Spring-Security-OAuth2-Config/src/main/java/cc/mrbird/security/validate/smscode/SmsAuthenticationToken.java ================================================ package cc.mrbird.security.validate.smscode; import org.springframework.security.authentication.AbstractAuthenticationToken; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.SpringSecurityCoreVersion; import java.util.Collection; public class SmsAuthenticationToken extends AbstractAuthenticationToken { private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID; private final Object principal; public SmsAuthenticationToken(String mobile) { super(null); this.principal = mobile; setAuthenticated(false); } public SmsAuthenticationToken(Object principal, Collection authorities) { super(authorities); this.principal = principal; super.setAuthenticated(true); // must use super, as we override } @Override public Object getCredentials() { return null; } public Object getPrincipal() { return this.principal; } public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException { if (isAuthenticated) { throw new IllegalArgumentException( "Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead"); } super.setAuthenticated(false); } @Override public void eraseCredentials() { super.eraseCredentials(); } } ================================================ FILE: 65.Spring-Security-OAuth2-Config/src/main/java/cc/mrbird/security/validate/smscode/SmsCode.java ================================================ package cc.mrbird.security.validate.smscode; public class SmsCode { private String code; public SmsCode(String code) { this.code = code; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } } ================================================ FILE: 65.Spring-Security-OAuth2-Config/src/main/java/cc/mrbird/security/validate/smscode/SmsCodeFilter.java ================================================ package cc.mrbird.security.validate.smscode; import cc.mrbird.security.service.RedisCodeService; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.AuthenticationServiceException; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.stereotype.Component; import org.springframework.web.bind.ServletRequestUtils; import org.springframework.web.context.request.ServletWebRequest; import org.springframework.web.filter.OncePerRequestFilter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @Component public class SmsCodeFilter extends OncePerRequestFilter { @Autowired private AuthenticationFailureHandler authenticationFailureHandler; @Autowired private RedisCodeService redisCodeService; @Override protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException { if (StringUtils.equalsIgnoreCase("/login/mobile", httpServletRequest.getRequestURI()) && StringUtils.equalsIgnoreCase(httpServletRequest.getMethod(), "post")) { try { validateCode(new ServletWebRequest(httpServletRequest)); } catch (Exception e) { authenticationFailureHandler.onAuthenticationFailure(httpServletRequest, httpServletResponse, new AuthenticationServiceException(e.getMessage())); return; } } filterChain.doFilter(httpServletRequest, httpServletResponse); } private void validateCode(ServletWebRequest servletWebRequest) throws Exception { String smsCodeInRequest = ServletRequestUtils.getStringParameter(servletWebRequest.getRequest(), "smsCode"); String mobileInRequest = ServletRequestUtils.getStringParameter(servletWebRequest.getRequest(), "mobile"); String codeInRedis = redisCodeService.get(servletWebRequest, mobileInRequest); if (StringUtils.isBlank(smsCodeInRequest)) { throw new Exception("验证码不能为空!"); } if (codeInRedis == null) { throw new Exception("验证码已过期!"); } if (!StringUtils.equalsIgnoreCase(codeInRedis, smsCodeInRequest)) { throw new Exception("验证码不正确!"); } redisCodeService.remove(servletWebRequest, mobileInRequest); } } ================================================ FILE: 65.Spring-Security-OAuth2-Config/src/main/resources/application.yml ================================================ security: oauth2: client: client-id: test client-secret: test1234 ================================================ FILE: 66.Spring-Security-OAuth2-SSO/pom.xml ================================================ 4.0.0 pom sso-application-one sso-application-two sso-server org.springframework.boot spring-boot-starter-parent 2.1.6.RELEASE cc.mrbird sso 0.0.1-SNAPSHOT sso Demo project for Spring Boot 1.8 Greenwich.SR1 org.springframework.boot spring-boot-starter-web org.springframework.cloud spring-cloud-starter org.springframework.cloud spring-cloud-starter-oauth2 org.springframework.cloud spring-cloud-starter-security org.apache.commons commons-lang3 org.springframework.cloud spring-cloud-dependencies ${spring-cloud.version} pom import org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 66.Spring-Security-OAuth2-SSO/sso-application-one/pom.xml ================================================ sso cc.mrbird 0.0.1-SNAPSHOT 4.0.0 sso-application-one ================================================ FILE: 66.Spring-Security-OAuth2-SSO/sso-application-one/src/main/java/cc/mrbird/sso/SsoApplicaitonOne.java ================================================ package cc.mrbird.sso; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso; import org.springframework.boot.builder.SpringApplicationBuilder; /** * @author MrBird */ @EnableOAuth2Sso @SpringBootApplication public class SsoApplicaitonOne { public static void main(String[] args) { new SpringApplicationBuilder(SsoApplicaitonOne.class).run(args); } } ================================================ FILE: 66.Spring-Security-OAuth2-SSO/sso-application-one/src/main/java/cc/mrbird/sso/client/config/WebSecurityConfigurer.java ================================================ package cc.mrbird.sso.client.config; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.Order; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; /** * @author MrBird */ @Order(101) @Configuration @EnableGlobalMethodSecurity(prePostEnabled = true) public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter { } ================================================ FILE: 66.Spring-Security-OAuth2-SSO/sso-application-one/src/main/java/cc/mrbird/sso/client/controller/UserController.java ================================================ package cc.mrbird.sso.client.controller; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import java.security.Principal;; /** * @author MrBird */ @RestController public class UserController { @GetMapping("user") public Principal user(Principal principal) { return principal; } @GetMapping("auth/test1") @PreAuthorize("hasAuthority('user:add')") public String authTest1(){ return "您拥有'user:add'权限"; } @GetMapping("auth/test2") @PreAuthorize("hasAuthority('user:update')") public String authTest2(){ return "您拥有'user:update'权限"; } } ================================================ FILE: 66.Spring-Security-OAuth2-SSO/sso-application-one/src/main/resources/application.yml ================================================ security: oauth2: client: client-id: app-a client-secret: app-a-1234 user-authorization-uri: http://127.0.0.1:8080/server/oauth/authorize access-token-uri: http://127.0.0.1:8080/server/oauth/token resource: jwt: key-uri: http://127.0.0.1:8080/server/oauth/token_key server: port: 9090 servlet: context-path: /app1 ================================================ FILE: 66.Spring-Security-OAuth2-SSO/sso-application-one/src/main/resources/static/index.html ================================================ 管理系统一

管理系统一

跳转到管理系统二 ================================================ FILE: 66.Spring-Security-OAuth2-SSO/sso-application-two/pom.xml ================================================ sso cc.mrbird 0.0.1-SNAPSHOT 4.0.0 sso-application-two ================================================ FILE: 66.Spring-Security-OAuth2-SSO/sso-application-two/src/main/java/cc/mrbird/sso/SsoApplicaitonTwo.java ================================================ package cc.mrbird.sso; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso; import org.springframework.boot.builder.SpringApplicationBuilder; /** * @author MrBird */ @EnableOAuth2Sso @SpringBootApplication public class SsoApplicaitonTwo { public static void main(String[] args) { new SpringApplicationBuilder(SsoApplicaitonTwo.class).run(args); } } ================================================ FILE: 66.Spring-Security-OAuth2-SSO/sso-application-two/src/main/java/cc/mrbird/sso/client/controller/UserController.java ================================================ package cc.mrbird.sso.client.controller; import org.springframework.security.core.Authentication; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; /** * @author MrBird */ @RestController public class UserController { @GetMapping("user") public Authentication user(Authentication authentication) { return authentication; } } ================================================ FILE: 66.Spring-Security-OAuth2-SSO/sso-application-two/src/main/resources/application.yml ================================================ security: oauth2: client: client-id: app-b client-secret: app-b-1234 user-authorization-uri: http://127.0.0.1:8080/server/oauth/authorize access-token-uri: http://127.0.0.1:8080/server/oauth/token resource: jwt: key-uri: http://127.0.0.1:8080/server/oauth/token_key server: port: 9091 servlet: context-path: /app2 ================================================ FILE: 66.Spring-Security-OAuth2-SSO/sso-application-two/src/main/resources/static/index.html ================================================ 管理系统二

管理系统二

跳转到管理系统一 ================================================ FILE: 66.Spring-Security-OAuth2-SSO/sso-server/pom.xml ================================================ sso cc.mrbird 0.0.1-SNAPSHOT 4.0.0 sso-server ================================================ FILE: 66.Spring-Security-OAuth2-SSO/sso-server/src/main/java/cc/mrbird/sso/SsoServerApplication.java ================================================ package cc.mrbird.sso; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.builder.SpringApplicationBuilder; /** * @author MrBird */ @SpringBootApplication public class SsoServerApplication { public static void main(String[] args) { new SpringApplicationBuilder(SsoServerApplication.class).run(args); } } ================================================ FILE: 66.Spring-Security-OAuth2-SSO/sso-server/src/main/java/cc/mrbird/sso/server/config/SsoAuthorizationServerConfig.java ================================================ package cc.mrbird.sso.server.config; import cc.mrbird.sso.server.service.UserDetailService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer; import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter; import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer; import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer; import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer; import org.springframework.security.oauth2.provider.token.TokenStore; import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; import org.springframework.security.oauth2.provider.token.store.JwtTokenStore; /** * @author MrBird */ @Configuration @EnableAuthorizationServer public class SsoAuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { @Autowired private PasswordEncoder passwordEncoder; @Autowired private UserDetailService userDetailService; @Bean public TokenStore jwtTokenStore() { return new JwtTokenStore(jwtAccessTokenConverter()); } @Bean public JwtAccessTokenConverter jwtAccessTokenConverter() { JwtAccessTokenConverter accessTokenConverter = new JwtAccessTokenConverter(); accessTokenConverter.setSigningKey("test_key"); return accessTokenConverter; } @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory() .withClient("app-a") .secret(passwordEncoder.encode("app-a-1234")) .authorizedGrantTypes("refresh_token","authorization_code") .accessTokenValiditySeconds(3600) .scopes("all") .autoApprove(true) .redirectUris("http://127.0.0.1:9090/app1/login") .and() .withClient("app-b") .secret(passwordEncoder.encode("app-b-1234")) .authorizedGrantTypes("refresh_token","authorization_code") .accessTokenValiditySeconds(7200) .scopes("all") .autoApprove(true) .redirectUris("http://127.0.0.1:9091/app2/login"); } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) { endpoints.tokenStore(jwtTokenStore()) .accessTokenConverter(jwtAccessTokenConverter()) .userDetailsService(userDetailService); } @Override public void configure(AuthorizationServerSecurityConfigurer security) { security.tokenKeyAccess("isAuthenticated()"); // 获取密钥需要身份认证 } } ================================================ FILE: 66.Spring-Security-OAuth2-SSO/sso-server/src/main/java/cc/mrbird/sso/server/config/WebSecurityConfig.java ================================================ package cc.mrbird.sso.server.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; /** * @author MrBird */ @Configuration public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Override protected void configure(HttpSecurity http) throws Exception { http.formLogin() .and() .authorizeRequests() .anyRequest() .authenticated(); } } ================================================ FILE: 66.Spring-Security-OAuth2-SSO/sso-server/src/main/java/cc/mrbird/sso/server/domain/MyUser.java ================================================ package cc.mrbird.sso.server.domain; import java.io.Serializable; public class MyUser implements Serializable { private static final long serialVersionUID = 3497935890426858541L; private String userName; private String password; private boolean accountNonExpired = true; private boolean accountNonLocked= true; private boolean credentialsNonExpired= true; private boolean enabled= true; public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public boolean isAccountNonExpired() { return accountNonExpired; } public void setAccountNonExpired(boolean accountNonExpired) { this.accountNonExpired = accountNonExpired; } public boolean isAccountNonLocked() { return accountNonLocked; } public void setAccountNonLocked(boolean accountNonLocked) { this.accountNonLocked = accountNonLocked; } public boolean isCredentialsNonExpired() { return credentialsNonExpired; } public void setCredentialsNonExpired(boolean credentialsNonExpired) { this.credentialsNonExpired = credentialsNonExpired; } public boolean isEnabled() { return enabled; } public void setEnabled(boolean enabled) { this.enabled = enabled; } } ================================================ FILE: 66.Spring-Security-OAuth2-SSO/sso-server/src/main/java/cc/mrbird/sso/server/service/UserDetailService.java ================================================ package cc.mrbird.sso.server.service; import cc.mrbird.sso.server.domain.MyUser; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.crypto.password.PasswordEncoder; /** * @author MrBird */ @Configuration public class UserDetailService implements UserDetailsService { @Autowired private PasswordEncoder passwordEncoder; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { MyUser user = new MyUser(); user.setUserName(username); user.setPassword(this.passwordEncoder.encode("123456")); return new User(username, user.getPassword(), user.isEnabled(), user.isAccountNonExpired(), user.isCredentialsNonExpired(), user.isAccountNonLocked(), AuthorityUtils.commaSeparatedStringToAuthorityList("user:add")); } } ================================================ FILE: 66.Spring-Security-OAuth2-SSO/sso-server/src/main/resources/application.yml ================================================ server: port: 8080 servlet: context-path: /server ================================================ FILE: 67.spring-batch-start/pom.xml ================================================ 4.0.0 org.springframework.boot spring-boot-starter-parent 2.2.5.RELEASE cc.mrbird spring-batch-start 0.0.1-SNAPSHOT spring-batch-start Demo project for Spring Boot 1.8 org.springframework.boot spring-boot-starter-batch mysql mysql-connector-java org.springframework.boot spring-boot-starter-jdbc org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 67.spring-batch-start/src/main/java/cc/mrbird/batch/SpringBatchStartApplication.java ================================================ package cc.mrbird.batch; import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication @EnableBatchProcessing public class SpringBatchStartApplication { public static void main(String[] args) { SpringApplication.run(SpringBatchStartApplication.class, args); } } ================================================ FILE: 67.spring-batch-start/src/main/java/cc/mrbird/batch/decider/MyDecider.java ================================================ package cc.mrbird.batch.decider; import org.springframework.batch.core.JobExecution; import org.springframework.batch.core.StepExecution; import org.springframework.batch.core.job.flow.FlowExecutionStatus; import org.springframework.batch.core.job.flow.JobExecutionDecider; import org.springframework.stereotype.Component; import java.time.DayOfWeek; import java.time.LocalDate; /** * @author MrBird */ @Component public class MyDecider implements JobExecutionDecider { @Override public FlowExecutionStatus decide(JobExecution jobExecution, StepExecution stepExecution) { LocalDate now = LocalDate.now(); DayOfWeek dayOfWeek = now.getDayOfWeek(); if (dayOfWeek == DayOfWeek.SATURDAY || dayOfWeek == DayOfWeek.SUNDAY) { return new FlowExecutionStatus("weekend"); } else { return new FlowExecutionStatus("workingDay"); } } } ================================================ FILE: 67.spring-batch-start/src/main/java/cc/mrbird/batch/job/DeciderJobDemo.java ================================================ package cc.mrbird.batch.job; import cc.mrbird.batch.decider.MyDecider; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; import org.springframework.batch.repeat.RepeatStatus; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; /** * @author MrBird */ @Component public class DeciderJobDemo { @Autowired private JobBuilderFactory jobBuilderFactory; @Autowired private StepBuilderFactory stepBuilderFactory; @Autowired private MyDecider myDecider; @Bean public Job deciderJob() { return jobBuilderFactory.get("deciderJob") .start(step1()) .next(myDecider) .from(myDecider).on("weekend").to(step2()) .from(myDecider).on("workingDay").to(step3()) .from(step3()).on("*").to(step4()) .end() .build(); } private Step step1() { return stepBuilderFactory.get("step1") .tasklet((stepContribution, chunkContext) -> { System.out.println("执行步骤一操作。。。"); return RepeatStatus.FINISHED; }).build(); } private Step step2() { return stepBuilderFactory.get("step2") .tasklet((stepContribution, chunkContext) -> { System.out.println("执行步骤二操作。。。"); return RepeatStatus.FINISHED; }).build(); } private Step step3() { return stepBuilderFactory.get("step3") .tasklet((stepContribution, chunkContext) -> { System.out.println("执行步骤三操作。。。"); return RepeatStatus.FINISHED; }).build(); } private Step step4() { return stepBuilderFactory.get("step4") .tasklet((stepContribution, chunkContext) -> { System.out.println("执行步骤四操作。。。"); return RepeatStatus.FINISHED; }).build(); } } ================================================ FILE: 67.spring-batch-start/src/main/java/cc/mrbird/batch/job/FirstJobDemo.java ================================================ package cc.mrbird.batch.job; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; import org.springframework.batch.repeat.RepeatStatus; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; /** * @author MrBird */ @Component public class FirstJobDemo { @Autowired private JobBuilderFactory jobBuilderFactory; @Autowired private StepBuilderFactory stepBuilderFactory; @Bean public Job firstJob() { return jobBuilderFactory.get("firstJob") .start(step()) .build(); } private Step step() { return stepBuilderFactory.get("step") .tasklet((contribution, chunkContext) -> { System.out.println("执行步骤...."); return RepeatStatus.FINISHED; }).build(); } } ================================================ FILE: 67.spring-batch-start/src/main/java/cc/mrbird/batch/job/FlowJobDemo.java ================================================ package cc.mrbird.batch.job; import org.springframework.batch.core.ExitStatus; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; import org.springframework.batch.core.job.builder.FlowBuilder; import org.springframework.batch.core.job.flow.Flow; import org.springframework.batch.repeat.RepeatStatus; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; /** * @author MrBird */ @Component public class FlowJobDemo { @Autowired private JobBuilderFactory jobBuilderFactory; @Autowired private StepBuilderFactory stepBuilderFactory; @Bean public Job flowJob() { return jobBuilderFactory.get("flowJob") .start(flow()) .next(step3()) .end() .build(); } private Step step1() { return stepBuilderFactory.get("step1") .tasklet((stepContribution, chunkContext) -> { System.out.println("执行步骤一操作。。。"); return RepeatStatus.FINISHED; }).build(); } private Step step2() { return stepBuilderFactory.get("step2") .tasklet((stepContribution, chunkContext) -> { System.out.println("执行步骤二操作。。。"); return RepeatStatus.FINISHED; }).build(); } private Step step3() { return stepBuilderFactory.get("step3") .tasklet((stepContribution, chunkContext) -> { System.out.println("执行步骤三操作。。。"); return RepeatStatus.FINISHED; }).build(); } // 创建一个flow对象,包含若干个step private Flow flow() { return new FlowBuilder("flow") .start(step1()) .next(step2()) .build(); } } ================================================ FILE: 67.spring-batch-start/src/main/java/cc/mrbird/batch/job/MultiStepJobDemo.java ================================================ package cc.mrbird.batch.job; import org.springframework.batch.core.ExitStatus; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; import org.springframework.batch.repeat.RepeatStatus; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; /** * @author MrBird */ @Component public class MultiStepJobDemo { @Autowired private JobBuilderFactory jobBuilderFactory; @Autowired private StepBuilderFactory stepBuilderFactory; @Bean public Job multiStepJob() { // return jobBuilderFactory.get("multiStepJob") // .start(step1()) // .next(step2()) // .next(step3()) // .build(); return jobBuilderFactory.get("multiStepJob2") .start(step1()) .on(ExitStatus.COMPLETED.getExitCode()).to(step2()) .from(step2()) .on(ExitStatus.COMPLETED.getExitCode()).to(step3()) .from(step3()).end() .build(); } private Step step1() { return stepBuilderFactory.get("step1") .tasklet((stepContribution, chunkContext) -> { System.out.println("执行步骤一操作。。。"); return RepeatStatus.FINISHED; }).build(); } private Step step2() { return stepBuilderFactory.get("step2") .tasklet((stepContribution, chunkContext) -> { System.out.println("执行步骤二操作。。。"); return RepeatStatus.FINISHED; }).build(); } private Step step3() { return stepBuilderFactory.get("step3") .tasklet((stepContribution, chunkContext) -> { System.out.println("执行步骤三操作。。。"); return RepeatStatus.FINISHED; }).build(); } } ================================================ FILE: 67.spring-batch-start/src/main/java/cc/mrbird/batch/job/NestedJobDemo.java ================================================ package cc.mrbird.batch.job; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; import org.springframework.batch.core.launch.JobLauncher; import org.springframework.batch.core.repository.JobRepository; import org.springframework.batch.core.step.builder.JobStepBuilder; import org.springframework.batch.core.step.builder.StepBuilder; import org.springframework.batch.repeat.RepeatStatus; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; import org.springframework.transaction.PlatformTransactionManager; /** * @author MrBird */ @Component public class NestedJobDemo { @Autowired private JobBuilderFactory jobBuilderFactory; @Autowired private StepBuilderFactory stepBuilderFactory; @Autowired private JobLauncher jobLauncher; @Autowired private JobRepository jobRepository; @Autowired private PlatformTransactionManager platformTransactionManager; // 父任务 @Bean public Job parentJob() { return jobBuilderFactory.get("parentJob") .start(childJobOneStep()) .next(childJobTwoStep()) .build(); } // 将任务转换为特殊的步骤 private Step childJobOneStep() { return new JobStepBuilder(new StepBuilder("childJobOneStep")) .job(childJobOne()) .launcher(jobLauncher) .repository(jobRepository) .transactionManager(platformTransactionManager) .build(); } // 将任务转换为特殊的步骤 private Step childJobTwoStep() { return new JobStepBuilder(new StepBuilder("childJobTwoStep")) .job(childJobTwo()) .launcher(jobLauncher) .repository(jobRepository) .transactionManager(platformTransactionManager) .build(); } // 子任务一 private Job childJobOne() { return jobBuilderFactory.get("childJobOne") .start( stepBuilderFactory.get("childJobOneStep") .tasklet((stepContribution, chunkContext) -> { System.out.println("子任务一执行步骤。。。"); return RepeatStatus.FINISHED; }).build() ).build(); } // 子任务二 private Job childJobTwo() { return jobBuilderFactory.get("childJobTwo") .start( stepBuilderFactory.get("childJobTwoStep") .tasklet((stepContribution, chunkContext) -> { System.out.println("子任务二执行步骤。。。"); return RepeatStatus.FINISHED; }).build() ).build(); } } ================================================ FILE: 67.spring-batch-start/src/main/java/cc/mrbird/batch/job/SplitJobDemo.java ================================================ package cc.mrbird.batch.job; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; import org.springframework.batch.core.job.builder.FlowBuilder; import org.springframework.batch.core.job.flow.Flow; import org.springframework.batch.repeat.RepeatStatus; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.core.task.SimpleAsyncTaskExecutor; import org.springframework.stereotype.Component; /** * @author MrBird */ @Component public class SplitJobDemo { @Autowired private JobBuilderFactory jobBuilderFactory; @Autowired private StepBuilderFactory stepBuilderFactory; @Bean public Job splitJob() { return jobBuilderFactory.get("splitJob") .start(flow1()) .split(new SimpleAsyncTaskExecutor()).add(flow2()) .end() .build(); } private Step step1() { return stepBuilderFactory.get("step1") .tasklet((stepContribution, chunkContext) -> { System.out.println("执行步骤一操作。。。"); return RepeatStatus.FINISHED; }).build(); } private Step step2() { return stepBuilderFactory.get("step2") .tasklet((stepContribution, chunkContext) -> { System.out.println("执行步骤二操作。。。"); return RepeatStatus.FINISHED; }).build(); } private Step step3() { return stepBuilderFactory.get("step3") .tasklet((stepContribution, chunkContext) -> { System.out.println("执行步骤三操作。。。"); return RepeatStatus.FINISHED; }).build(); } private Flow flow1() { return new FlowBuilder("flow1") .start(step1()) .next(step2()) .build(); } private Flow flow2() { return new FlowBuilder("flow2") .start(step3()) .build(); } } ================================================ FILE: 67.spring-batch-start/src/main/resources/application.yml ================================================ spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://127.0.0.1:3306/springbatch username: root password: 123456 ================================================ FILE: 68.spring-batch-itemreader/pom.xml ================================================ 4.0.0 org.springframework.boot spring-boot-starter-parent 2.2.5.RELEASE cc.mrbird spring-batch-itemreader 0.0.1-SNAPSHOT spring-batch-itemreader Demo project for Spring Boot 1.8 org.springframework.boot spring-boot-starter-batch mysql mysql-connector-java org.springframework.boot spring-boot-starter-jdbc org.springframework spring-oxm com.thoughtworks.xstream xstream 1.4.11.1 org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 68.spring-batch-itemreader/src/main/java/cc/mrbird/batch/SpringBatchItemreaderApplication.java ================================================ package cc.mrbird.batch; import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication @EnableBatchProcessing public class SpringBatchItemreaderApplication { public static void main(String[] args) { SpringApplication.run(SpringBatchItemreaderApplication.class, args); } } ================================================ FILE: 68.spring-batch-itemreader/src/main/java/cc/mrbird/batch/entity/TestData.java ================================================ package cc.mrbird.batch.entity; /** * @author MrBird */ public class TestData { private int id; private String field1; private String field2; private String field3; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getField1() { return field1; } public void setField1(String field1) { this.field1 = field1; } public String getField2() { return field2; } public void setField2(String field2) { this.field2 = field2; } public String getField3() { return field3; } public void setField3(String field3) { this.field3 = field3; } @Override public String toString() { return "TestData{" + "id=" + id + ", field1='" + field1 + '\'' + ", field2='" + field2 + '\'' + ", field3='" + field3 + '\'' + '}'; } } ================================================ FILE: 68.spring-batch-itemreader/src/main/java/cc/mrbird/batch/job/DataSourceItemReaderDemo.java ================================================ package cc.mrbird.batch.job; import cc.mrbird.batch.entity.TestData; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; import org.springframework.batch.item.ItemReader; import org.springframework.batch.item.database.JdbcPagingItemReader; import org.springframework.batch.item.database.Order; import org.springframework.batch.item.database.support.MySqlPagingQueryProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; import javax.sql.DataSource; import java.util.HashMap; import java.util.Map; /** * @author MrBird */ @Component public class DataSourceItemReaderDemo { @Autowired private JobBuilderFactory jobBuilderFactory; @Autowired private StepBuilderFactory stepBuilderFactory; // 注入数据源 @Autowired private DataSource dataSource; @Bean public Job dataSourceItemReaderJob() throws Exception { return jobBuilderFactory.get("dataSourceItemReaderJob") .start(step()) .build(); } private Step step() throws Exception { return stepBuilderFactory.get("step") .chunk(2) .reader(dataSourceItemReader()) .writer(list -> list.forEach(System.out::println)) .build(); } private ItemReader dataSourceItemReader() throws Exception { JdbcPagingItemReader reader = new JdbcPagingItemReader<>(); reader.setDataSource(dataSource); // 设置数据源 reader.setFetchSize(5); // 每次取多少条记录 reader.setPageSize(5); // 设置每页数据量 // 指定sql查询语句 select id,field1,field2,field3 from TEST MySqlPagingQueryProvider provider = new MySqlPagingQueryProvider(); provider.setSelectClause("id,field1,field2,field3"); //设置查询字段 provider.setFromClause("from TEST"); // 设置从哪张表查询 // 将读取到的数据转换为TestData对象 reader.setRowMapper((resultSet, rowNum) -> { TestData data = new TestData(); data.setId(resultSet.getInt(1)); data.setField1(resultSet.getString(2)); // 读取第一个字段,类型为String data.setField2(resultSet.getString(3)); data.setField3(resultSet.getString(4)); return data; }); Map sort = new HashMap<>(1); sort.put("id", Order.ASCENDING); provider.setSortKeys(sort); // 设置排序,通过id 升序 reader.setQueryProvider(provider); // 设置namedParameterJdbcTemplate等属性 reader.afterPropertiesSet(); return reader; } } ================================================ FILE: 68.spring-batch-itemreader/src/main/java/cc/mrbird/batch/job/FileItemReaderDemo.java ================================================ package cc.mrbird.batch.job; import cc.mrbird.batch.entity.TestData; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; import org.springframework.batch.item.ItemReader; import org.springframework.batch.item.file.FlatFileItemReader; import org.springframework.batch.item.file.mapping.DefaultLineMapper; import org.springframework.batch.item.file.transform.DelimitedLineTokenizer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.core.io.ClassPathResource; import org.springframework.stereotype.Component; /** * @author MrBird */ @Component public class FileItemReaderDemo { // 任务创建工厂 @Autowired private JobBuilderFactory jobBuilderFactory; // 步骤创建工厂 @Autowired private StepBuilderFactory stepBuilderFactory; @Bean public Job fileItemReaderJob() { return jobBuilderFactory.get("fileItemReaderJob") .start(step()) .build(); } private Step step() { return stepBuilderFactory.get("step") .chunk(2) .reader(fileItemReader()) .writer(list -> list.forEach(System.out::println)) .build(); } private ItemReader fileItemReader() { FlatFileItemReader reader = new FlatFileItemReader<>(); reader.setResource(new ClassPathResource("file")); // 设置文件资源地址 reader.setLinesToSkip(1); // 忽略第一行 // AbstractLineTokenizer的三个实现类之一,以固定分隔符处理行数据读取, // 使用默认构造器的时候,使用逗号作为分隔符,也可以通过有参构造器来指定分隔符 DelimitedLineTokenizer tokenizer = new DelimitedLineTokenizer(); // 设置属性名,类似于表头 tokenizer.setNames("id", "field1", "field2", "field3"); // 将每行数据转换为TestData对象 DefaultLineMapper mapper = new DefaultLineMapper<>(); mapper.setLineTokenizer(tokenizer); // 设置映射方式 mapper.setFieldSetMapper(fieldSet -> { TestData data = new TestData(); data.setId(fieldSet.readInt("id")); data.setField1(fieldSet.readString("field1")); data.setField2(fieldSet.readString("field2")); data.setField3(fieldSet.readString("field3")); return data; }); reader.setLineMapper(mapper); return reader; } } ================================================ FILE: 68.spring-batch-itemreader/src/main/java/cc/mrbird/batch/job/JSONFileItemReaderDemo.java ================================================ package cc.mrbird.batch.job; import cc.mrbird.batch.entity.TestData; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; import org.springframework.batch.item.ItemReader; import org.springframework.batch.item.json.JacksonJsonObjectReader; import org.springframework.batch.item.json.JsonItemReader; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.core.io.ClassPathResource; import org.springframework.stereotype.Component; /** * @author MrBird */ @Component public class JSONFileItemReaderDemo { @Autowired private JobBuilderFactory jobBuilderFactory; @Autowired private StepBuilderFactory stepBuilderFactory; @Bean public Job jsonFileItemReaderJob() { return jobBuilderFactory.get("jsonFileItemReaderJob") .start(step()) .build(); } private Step step() { return stepBuilderFactory.get("step") .chunk(2) .reader(jsonItemReader()) .writer(list -> list.forEach(System.out::println)) .build(); } private ItemReader jsonItemReader() { // 设置json文件地址 ClassPathResource resource = new ClassPathResource("file.json"); // 设置json文件转换的目标对象类型 JacksonJsonObjectReader jacksonJsonObjectReader = new JacksonJsonObjectReader<>(TestData.class); JsonItemReader reader = new JsonItemReader<>(resource, jacksonJsonObjectReader); // 给reader设置一个别名 reader.setName("testDataJsonItemReader"); return reader; } } ================================================ FILE: 68.spring-batch-itemreader/src/main/java/cc/mrbird/batch/job/MultiFileIteamReaderDemo.java ================================================ package cc.mrbird.batch.job; import cc.mrbird.batch.entity.TestData; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; import org.springframework.batch.item.ItemReader; import org.springframework.batch.item.file.FlatFileItemReader; import org.springframework.batch.item.file.MultiResourceItemReader; import org.springframework.batch.item.file.mapping.DefaultLineMapper; import org.springframework.batch.item.file.transform.DelimitedLineTokenizer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import org.springframework.stereotype.Component; /** * @author MrBird * * 5. 演示多文件读取 */ @Component public class MultiFileIteamReaderDemo { @Autowired private JobBuilderFactory jobBuilderFactory; @Autowired private StepBuilderFactory stepBuilderFactory; @Bean public Job multiFileItemReaderJob() { return jobBuilderFactory.get("multiFileItemReaderJob") .start(step()) .build(); } private Step step() { return stepBuilderFactory.get("step") .chunk(2) .reader(multiFileItemReader()) .writer(list -> list.forEach(System.out::println)) .build(); } private ItemReader multiFileItemReader() { MultiResourceItemReader reader = new MultiResourceItemReader<>(); reader.setDelegate(fileItemReader()); // 设置文件读取代理,方法可以使用前面文件读取中的例子 Resource[] resources = new Resource[]{ new ClassPathResource("file1"), new ClassPathResource("file2") }; reader.setResources(resources); // 设置多文件源 return reader; } private FlatFileItemReader fileItemReader() { FlatFileItemReader reader = new FlatFileItemReader<>(); reader.setLinesToSkip(1); // 忽略第一行 // AbstractLineTokenizer的三个实现类之一,以固定分隔符处理行数据读取, // 使用默认构造器的时候,使用逗号作为分隔符,也可以通过有参构造器来指定分隔符 DelimitedLineTokenizer tokenizer = new DelimitedLineTokenizer(); // 设置属姓名,类似于表头 tokenizer.setNames("id", "field1", "field2", "field3"); // 将每行数据转换为TestData对象 DefaultLineMapper mapper = new DefaultLineMapper<>(); mapper.setLineTokenizer(tokenizer); // 设置映射方式 mapper.setFieldSetMapper(fieldSet -> { TestData data = new TestData(); data.setId(fieldSet.readInt("id")); data.setField1(fieldSet.readString("field1")); data.setField2(fieldSet.readString("field2")); data.setField3(fieldSet.readString("field3")); return data; }); reader.setLineMapper(mapper); return reader; } } ================================================ FILE: 68.spring-batch-itemreader/src/main/java/cc/mrbird/batch/job/MySimpleItemReaderDemo.java ================================================ package cc.mrbird.batch.job; import cc.mrbird.batch.reader.MySimpleIteamReader; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; import org.springframework.batch.item.ItemReader; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; import java.util.Arrays; import java.util.List; /** * @author MrBird */ @Component public class MySimpleItemReaderDemo { @Autowired private JobBuilderFactory jobBuilderFactory; @Autowired private StepBuilderFactory stepBuilderFactory; @Bean public Job mySimpleItemReaderJob() { return jobBuilderFactory.get("mySimpleItemReaderJob") .start(step()) .build(); } private Step step() { return stepBuilderFactory.get("step") .chunk(2) .reader(mySimpleItemReader()) .writer(list -> list.forEach(System.out::println)) // 简单输出,后面再详细介绍writer .build(); } private ItemReader mySimpleItemReader() { List data = Arrays.asList("java", "c++", "javascript", "python"); return new MySimpleIteamReader(data); } } ================================================ FILE: 68.spring-batch-itemreader/src/main/java/cc/mrbird/batch/job/XmlFileItemReaderDemo.java ================================================ package cc.mrbird.batch.job; import cc.mrbird.batch.entity.TestData; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; import org.springframework.batch.item.ItemReader; import org.springframework.batch.item.xml.StaxEventItemReader; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.core.io.ClassPathResource; import org.springframework.oxm.xstream.XStreamMarshaller; import org.springframework.stereotype.Component; import java.util.HashMap; import java.util.Map; /** * @author MrBird */ @Component public class XmlFileItemReaderDemo { @Autowired private JobBuilderFactory jobBuilderFactory; @Autowired private StepBuilderFactory stepBuilderFactory; @Bean public Job xmlFileItemReaderJob() { return jobBuilderFactory.get("xmlFileItemReaderJob") .start(step()) .build(); } private Step step() { return stepBuilderFactory.get("step") .chunk(2) .reader(xmlFileItemReader()) .writer(list -> list.forEach(System.out::println)) .build(); } private ItemReader xmlFileItemReader() { StaxEventItemReader reader = new StaxEventItemReader<>(); reader.setResource(new ClassPathResource("file.xml")); // 设置xml文件源 reader.setFragmentRootElementName("test"); // 指定xml文件的根标签 // 将xml数据转换为TestData对象 XStreamMarshaller marshaller = new XStreamMarshaller(); // 指定需要转换的目标数据类型 Map> map = new HashMap<>(1); map.put("test", TestData.class); marshaller.setAliases(map); reader.setUnmarshaller(marshaller); return reader; } } ================================================ FILE: 68.spring-batch-itemreader/src/main/java/cc/mrbird/batch/reader/MySimpleIteamReader.java ================================================ package cc.mrbird.batch.reader; import org.springframework.batch.item.ItemReader; import java.util.Iterator; import java.util.List; /** * @author MrBird */ public class MySimpleIteamReader implements ItemReader { private Iterator iterator; public MySimpleIteamReader(List data) { this.iterator = data.iterator(); } @Override public String read() { // 数据一个接着一个读取 return iterator.hasNext() ? iterator.next() : null; } } ================================================ FILE: 68.spring-batch-itemreader/src/main/resources/TEST.sql ================================================ /* Navicat Premium Data Transfer Source Server : localhost_mysql Source Server Type : MySQL Source Server Version : 50724 Source Host : localhost:3306 Source Schema : springbatch Target Server Type : MySQL Target Server Version : 50724 File Encoding : 65001 Date: 07/03/2020 15:50:05 */ SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for TEST -- ---------------------------- DROP TABLE IF EXISTS `TEST`; CREATE TABLE `TEST` ( `id` bigint(10) NOT NULL COMMENT 'ID', `field1` varchar(10) NOT NULL COMMENT '字段一', `field2` varchar(10) NOT NULL COMMENT '字段二', `field3` varchar(10) NOT NULL COMMENT '字段三', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of TEST -- ---------------------------- BEGIN; INSERT INTO `TEST` VALUES (1, '11', '12', '13'); INSERT INTO `TEST` VALUES (2, '21', '22', '23'); INSERT INTO `TEST` VALUES (3, '31', '32', '33'); INSERT INTO `TEST` VALUES (4, '41', '42', '43'); INSERT INTO `TEST` VALUES (5, '51', '52', '53'); INSERT INTO `TEST` VALUES (6, '61', '62', '63'); COMMIT; SET FOREIGN_KEY_CHECKS = 1; ================================================ FILE: 68.spring-batch-itemreader/src/main/resources/application.yml ================================================ spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://127.0.0.1:3306/springbatch username: root password: 123456 ================================================ FILE: 68.spring-batch-itemreader/src/main/resources/file ================================================ // 演示文件数据读取 1,11,12,13 2,21,22,23 3,31,32,33 4,41,42,43 5,51,52,53 6,61,62,63 ================================================ FILE: 68.spring-batch-itemreader/src/main/resources/file.json ================================================ [ { "id": 1, "field1": "11", "field2": "12", "field3": "13" }, { "id": 2, "field1": "21", "field2": "22", "field3": "23" }, { "id": 3, "field1": "31", "field2": "32", "field3": "33" } ] ================================================ FILE: 68.spring-batch-itemreader/src/main/resources/file.xml ================================================ 1 11 12 13 2 21 22 23 3 31 32 33 4 41 42 43 5 51 52 53 6 61 62 63 ================================================ FILE: 68.spring-batch-itemreader/src/main/resources/file1 ================================================ // 演示文件数据读取 1,11,12,13 2,21,22,23 3,31,32,33 4,41,42,43 5,51,52,53 6,61,62,63 ================================================ FILE: 68.spring-batch-itemreader/src/main/resources/file2 ================================================ // 演示文件数据读取 7,71,72,73 8,81,82,83 ================================================ FILE: 69.spring-batch-itemwriter/pom.xml ================================================ 4.0.0 org.springframework.boot spring-boot-starter-parent 2.2.5.RELEASE cc.mrbird spring-batch-itemwriter 0.0.1-SNAPSHOT spring-batch-itemwriter Demo project for Spring Boot 1.8 org.springframework.boot spring-boot-starter-batch mysql mysql-connector-java org.springframework.boot spring-boot-starter-jdbc org.springframework spring-oxm com.thoughtworks.xstream xstream 1.4.11.1 org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 69.spring-batch-itemwriter/src/main/java/cc/mrbird/batch/SpringBatchItemwriterApplication.java ================================================ package cc.mrbird.batch; import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication @EnableBatchProcessing public class SpringBatchItemwriterApplication { public static void main(String[] args) { SpringApplication.run(SpringBatchItemwriterApplication.class, args); } } ================================================ FILE: 69.spring-batch-itemwriter/src/main/java/cc/mrbird/batch/entity/TestData.java ================================================ package cc.mrbird.batch.entity; /** * @author MrBird */ public class TestData { private int id; private String field1; private String field2; private String field3; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getField1() { return field1; } public void setField1(String field1) { this.field1 = field1; } public String getField2() { return field2; } public void setField2(String field2) { this.field2 = field2; } public String getField3() { return field3; } public void setField3(String field3) { this.field3 = field3; } @Override public String toString() { return "TestData{" + "id=" + id + ", field1='" + field1 + '\'' + ", field2='" + field2 + '\'' + ", field3='" + field3 + '\'' + '}'; } } ================================================ FILE: 69.spring-batch-itemwriter/src/main/java/cc/mrbird/batch/job/DatabaseItemWriterDemo.java ================================================ package cc.mrbird.batch.job; import cc.mrbird.batch.entity.TestData; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; import org.springframework.batch.item.ItemWriter; import org.springframework.batch.item.database.BeanPropertyItemSqlParameterSourceProvider; import org.springframework.batch.item.database.JdbcBatchItemWriter; import org.springframework.batch.item.support.ListItemReader; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; import javax.sql.DataSource; /** * @author MrBird */ @Component public class DatabaseItemWriterDemo { @Autowired private JobBuilderFactory jobBuilderFactory; @Autowired private StepBuilderFactory stepBuilderFactory; @Autowired private ListItemReader simpleReader; @Autowired private DataSource dataSource; @Bean public Job datasourceItemWriterJob() { return jobBuilderFactory.get("datasourceItemWriterJob") .start(step()) .build(); } private Step step() { return stepBuilderFactory.get("step") .chunk(2) .reader(simpleReader) .writer(dataSourceItemWriter()) .build(); } private ItemWriter dataSourceItemWriter() { // ItemWriter的实现类之一,mysql数据库数据写入使用JdbcBatchItemWriter, // 其他实现:MongoItemWriter,Neo4jItemWriter等 JdbcBatchItemWriter writer = new JdbcBatchItemWriter<>(); writer.setDataSource(dataSource); // 设置数据源 String sql = "insert into TEST(id,field1,field2,field3) values (:id,:field1,:field2,:field3)"; writer.setSql(sql); // 设置插入sql脚本 // 映射TestData对象属性到占位符中的属性 BeanPropertyItemSqlParameterSourceProvider provider = new BeanPropertyItemSqlParameterSourceProvider<>(); writer.setItemSqlParameterSourceProvider(provider); writer.afterPropertiesSet(); // 设置一些额外属性 return writer; } } ================================================ FILE: 69.spring-batch-itemwriter/src/main/java/cc/mrbird/batch/job/FileItemWriterDemo.java ================================================ package cc.mrbird.batch.job; import cc.mrbird.batch.entity.TestData; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; import org.springframework.batch.item.file.FlatFileItemWriter; import org.springframework.batch.item.file.transform.LineAggregator; import org.springframework.batch.item.support.ListItemReader; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.core.io.FileSystemResource; import org.springframework.stereotype.Component; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; /** * @author MrBird */ @Component public class FileItemWriterDemo { @Autowired private JobBuilderFactory jobBuilderFactory; @Autowired private StepBuilderFactory stepBuilderFactory; @Autowired private ListItemReader simpleReader; @Bean public Job fileItemWriterJob() throws Exception { return jobBuilderFactory.get("fileItemWriterJob") .start(step()) .build(); } private Step step() throws Exception { return stepBuilderFactory.get("step") .chunk(2) .reader(simpleReader) .writer(fileItemWriter()) .build(); } private FlatFileItemWriter fileItemWriter() throws Exception { FlatFileItemWriter writer = new FlatFileItemWriter<>(); FileSystemResource file = new FileSystemResource("/Users/mrbird/Desktop/file"); Path path = Paths.get(file.getPath()); if (!Files.exists(path)) { Files.createFile(path); } writer.setResource(file); // 设置目标文件路径 // 把读到的每个TestData对象转换为JSON字符串 LineAggregator aggregator = item -> { try { ObjectMapper mapper = new ObjectMapper(); return mapper.writeValueAsString(item); } catch (JsonProcessingException e) { e.printStackTrace(); } return ""; }; writer.setLineAggregator(aggregator); writer.afterPropertiesSet(); return writer; } } ================================================ FILE: 69.spring-batch-itemwriter/src/main/java/cc/mrbird/batch/job/JsonFileItemWriterDemo.java ================================================ package cc.mrbird.batch.job; import cc.mrbird.batch.entity.TestData; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; import org.springframework.batch.item.json.JacksonJsonObjectMarshaller; import org.springframework.batch.item.json.JsonFileItemWriter; import org.springframework.batch.item.support.ListItemReader; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.core.io.FileSystemResource; import org.springframework.stereotype.Component; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; /** * @author MrBird */ @Component public class JsonFileItemWriterDemo { @Autowired private JobBuilderFactory jobBuilderFactory; @Autowired private StepBuilderFactory stepBuilderFactory; @Autowired private ListItemReader simpleReader; @Bean public Job jsonFileItemWriterJob() throws Exception { return jobBuilderFactory.get("jsonFileItemWriterJob") .start(step()) .build(); } private Step step() throws Exception { return stepBuilderFactory.get("step") .chunk(2) .reader(simpleReader) .writer(jsonFileItemWriter()) .build(); } private JsonFileItemWriter jsonFileItemWriter() throws IOException { // 文件输出目标地址 FileSystemResource file = new FileSystemResource("/Users/mrbird/Desktop/file.json"); Path path = Paths.get(file.getPath()); if (!Files.exists(path)) { Files.createFile(path); } // 将对象转换为json JacksonJsonObjectMarshaller marshaller = new JacksonJsonObjectMarshaller<>(); JsonFileItemWriter writer = new JsonFileItemWriter<>(file, marshaller); // 设置别名 writer.setName("testDatasonFileItemWriter"); return writer; } } ================================================ FILE: 69.spring-batch-itemwriter/src/main/java/cc/mrbird/batch/job/MultiFileItemWriteDemo.java ================================================ package cc.mrbird.batch.job; import cc.mrbird.batch.entity.TestData; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; import org.springframework.batch.item.ItemStreamWriter; import org.springframework.batch.item.ItemWriter; import org.springframework.batch.item.support.ClassifierCompositeItemWriter; import org.springframework.batch.item.support.CompositeItemWriter; import org.springframework.batch.item.support.ListItemReader; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.classify.Classifier; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; import javax.sql.DataSource; import java.util.Arrays; /** * @author MrBird */ @Component public class MultiFileItemWriteDemo { @Autowired private JobBuilderFactory jobBuilderFactory; @Autowired private StepBuilderFactory stepBuilderFactory; @Autowired private ListItemReader simpleReader; @Autowired private ItemStreamWriter fileItemWriter; @Autowired private ItemStreamWriter xmlFileItemWriter; @Bean public Job multiFileItemWriterJob() { return jobBuilderFactory.get("multiFileItemWriterJob6") .start(step()) .build(); } private Step step() { return stepBuilderFactory.get("step") .chunk(2) .reader(simpleReader) .writer(multiFileItemWriter()) // .stream(fileItemWriter) // .stream(xmlFileItemWriter) .build(); } // 输出数据到多个文件 private CompositeItemWriter multiFileItemWriter() { // 使用CompositeItemWriter代理 CompositeItemWriter writer = new CompositeItemWriter<>(); // 设置具体写代理 writer.setDelegates(Arrays.asList(fileItemWriter, xmlFileItemWriter)); return writer; } // 将数据分类,然后分别输出到对应的文件(此时需要将writer注册到ioc容器,否则报 // WriterNotOpenException: Writer must be open before it can be written to) private ClassifierCompositeItemWriter classifierMultiFileItemWriter() { ClassifierCompositeItemWriter writer = new ClassifierCompositeItemWriter<>(); writer.setClassifier((Classifier>) testData -> { try { // id能被2整除则输出到普通文本,否则输出到xml文本 return testData.getId() % 2 == 0 ? fileItemWriter : xmlFileItemWriter; } catch (Exception e) { e.printStackTrace(); } return null; }); return writer; } } ================================================ FILE: 69.spring-batch-itemwriter/src/main/java/cc/mrbird/batch/job/XmlFileItemWriterDemo.java ================================================ package cc.mrbird.batch.job; import cc.mrbird.batch.entity.TestData; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; import org.springframework.batch.item.support.ListItemReader; import org.springframework.batch.item.xml.StaxEventItemWriter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.core.io.FileSystemResource; import org.springframework.oxm.xstream.XStreamMarshaller; import org.springframework.stereotype.Component; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.HashMap; import java.util.Map; /** * @author MrBird */ @Component public class XmlFileItemWriterDemo { @Autowired private JobBuilderFactory jobBuilderFactory; @Autowired private StepBuilderFactory stepBuilderFactory; @Autowired private ListItemReader simpleReader; @Bean public Job xmlFileItemWriterJob() throws Exception { return jobBuilderFactory.get("xmlFileItemWriterJob") .start(step()) .build(); } private Step step() throws Exception { return stepBuilderFactory.get("step") .chunk(2) .reader(simpleReader) .writer(xmlFileItemWriter()) .build(); } private StaxEventItemWriter xmlFileItemWriter() throws IOException { StaxEventItemWriter writer = new StaxEventItemWriter<>(); // 通过XStreamMarshaller将TestData转换为xml XStreamMarshaller marshaller = new XStreamMarshaller(); Map> map = new HashMap<>(1); map.put("test", TestData.class); marshaller.setAliases(map); // 设置xml标签 writer.setRootTagName("tests"); // 设置根标签 writer.setMarshaller(marshaller); FileSystemResource file = new FileSystemResource("/Users/mrbird/Desktop/file.xml"); Path path = Paths.get(file.getPath()); if (!Files.exists(path)) { Files.createFile(path); } writer.setResource(file); // 设置目标文件路径 return writer; } } ================================================ FILE: 69.spring-batch-itemwriter/src/main/java/cc/mrbird/batch/reader/ItemReaderConfigure.java ================================================ package cc.mrbird.batch.reader; import cc.mrbird.batch.entity.TestData; import org.springframework.batch.item.support.ListItemReader; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.ArrayList; import java.util.List; /** * @author MrBird */ @Configuration public class ItemReaderConfigure { @Bean public ListItemReader simpleReader() { List data = new ArrayList<>(); TestData testData1 = new TestData(); testData1.setId(1); testData1.setField1("11"); testData1.setField2("12"); testData1.setField3("13"); data.add(testData1); TestData testData2 = new TestData(); testData2.setId(2); testData2.setField1("21"); testData2.setField2("22"); testData2.setField3("23"); data.add(testData2); return new ListItemReader<>(data); } } ================================================ FILE: 69.spring-batch-itemwriter/src/main/java/cc/mrbird/batch/writer/ItemWriterConfigure.java ================================================ package cc.mrbird.batch.writer; import cc.mrbird.batch.entity.TestData; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.batch.item.file.FlatFileItemWriter; import org.springframework.batch.item.file.transform.LineAggregator; import org.springframework.batch.item.xml.StaxEventItemWriter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.FileSystemResource; import org.springframework.oxm.xstream.XStreamMarshaller; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.HashMap; import java.util.Map; /** * @author MrBird */ @Configuration public class ItemWriterConfigure { @Bean public FlatFileItemWriter fileItemWriter() throws Exception { FlatFileItemWriter writer = new FlatFileItemWriter<>(); FileSystemResource file = new FileSystemResource("/Users/mrbird/Desktop/file"); Path path = Paths.get(file.getPath()); if (!Files.exists(path)) { Files.createFile(path); } writer.setResource(file); // 设置目标文件路径 // 把读到的每个TestData对象转换为字符串 LineAggregator aggregator = item -> { try { ObjectMapper mapper = new ObjectMapper(); return mapper.writeValueAsString(item); } catch (JsonProcessingException e) { e.printStackTrace(); } return ""; }; writer.setLineAggregator(aggregator); writer.afterPropertiesSet(); return writer; } @Bean public StaxEventItemWriter xmlFileItemWriter() throws Exception { StaxEventItemWriter writer = new StaxEventItemWriter<>(); // 通过XStreamMarshaller将TestData转换为xml XStreamMarshaller marshaller = new XStreamMarshaller(); Map> map = new HashMap<>(1); map.put("test", TestData.class); marshaller.setAliases(map); // 设置xml标签 writer.setRootTagName("tests"); // 设置根标签 writer.setMarshaller(marshaller); FileSystemResource file = new FileSystemResource("/Users/mrbird/Desktop/file.xml"); Path path = Paths.get(file.getPath()); if (!Files.exists(path)) { Files.createFile(path); } writer.setResource(file); // 设置目标文件路径 return writer; } } ================================================ FILE: 69.spring-batch-itemwriter/src/main/resources/application.yml ================================================ spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://127.0.0.1:3306/springbatch username: root password: 123456 ================================================ FILE: 70.spring-batch-itemprocessor/pom.xml ================================================ 4.0.0 org.springframework.boot spring-boot-starter-parent 2.2.5.RELEASE cc.mrbird spring-batch-itemprocessor 0.0.1-SNAPSHOT spring-batch-itemprocessor Demo project for Spring Boot 1.8 org.springframework.boot spring-boot-starter-batch mysql mysql-connector-java org.springframework.boot spring-boot-starter-jdbc org.springframework.boot spring-boot-starter-validation org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 70.spring-batch-itemprocessor/src/main/java/cc/mrbird/batch/SpringBatchItemprocessorApplication.java ================================================ package cc.mrbird.batch; import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication @EnableBatchProcessing public class SpringBatchItemprocessorApplication { public static void main(String[] args) { SpringApplication.run(SpringBatchItemprocessorApplication.class, args); } } ================================================ FILE: 70.spring-batch-itemprocessor/src/main/java/cc/mrbird/batch/entity/TestData.java ================================================ package cc.mrbird.batch.entity; import javax.validation.constraints.NotBlank; /** * @author MrBird */ public class TestData { private int id; private String field1; private String field2; @NotBlank private String field3; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getField1() { return field1; } public void setField1(String field1) { this.field1 = field1; } public String getField2() { return field2; } public void setField2(String field2) { this.field2 = field2; } public String getField3() { return field3; } public void setField3(String field3) { this.field3 = field3; } @Override public String toString() { return "TestData{" + "id=" + id + ", field1='" + field1 + '\'' + ", field2='" + field2 + '\'' + ", field3='" + field3 + '\'' + '}'; } } ================================================ FILE: 70.spring-batch-itemprocessor/src/main/java/cc/mrbird/batch/entity/job/BeanValidatingItemProcessorDemo.java ================================================ package cc.mrbird.batch.entity.job; import cc.mrbird.batch.entity.TestData; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; import org.springframework.batch.item.support.ListItemReader; import org.springframework.batch.item.validator.BeanValidatingItemProcessor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; /** * @author MrBird */ @Component public class BeanValidatingItemProcessorDemo { @Autowired private JobBuilderFactory jobBuilderFactory; @Autowired private StepBuilderFactory stepBuilderFactory; @Autowired private ListItemReader simpleReader; @Bean public Job beanValidatingItemProcessorJob() throws Exception { return jobBuilderFactory.get("beanValidatingItemProcessorJob") .start(step()) .build(); } private Step step() throws Exception { return stepBuilderFactory.get("step") .chunk(2) .reader(simpleReader) .processor(beanValidatingItemProcessor()) .writer(list -> list.forEach(System.out::println)) .build(); } private BeanValidatingItemProcessor beanValidatingItemProcessor() throws Exception { BeanValidatingItemProcessor beanValidatingItemProcessor = new BeanValidatingItemProcessor<>(); // 开启过滤,不符合规则的数据被过滤掉; beanValidatingItemProcessor.setFilter(true); beanValidatingItemProcessor.afterPropertiesSet(); return beanValidatingItemProcessor; } } ================================================ FILE: 70.spring-batch-itemprocessor/src/main/java/cc/mrbird/batch/entity/job/CompositeItemProcessorDemo.java ================================================ package cc.mrbird.batch.entity.job; import cc.mrbird.batch.entity.TestData; import cc.mrbird.batch.processor.TestDataFilterItemProcessor; import cc.mrbird.batch.processor.TestDataTransformItemPorcessor; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; import org.springframework.batch.item.ItemProcessor; import org.springframework.batch.item.support.CompositeItemProcessor; import org.springframework.batch.item.support.ListItemReader; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; import java.util.Arrays; import java.util.List; /** * @author MrBird */ @Component public class CompositeItemProcessorDemo { @Autowired private JobBuilderFactory jobBuilderFactory; @Autowired private StepBuilderFactory stepBuilderFactory; @Autowired private ListItemReader simpleReader; @Autowired private TestDataFilterItemProcessor testDataFilterItemProcessor; @Autowired private TestDataTransformItemPorcessor testDataTransformItemPorcessor; @Bean public Job compositeItemProcessorJob() { return jobBuilderFactory.get("compositeItemProcessorJob") .start(step()) .build(); } private Step step() { return stepBuilderFactory.get("step") .chunk(2) .reader(simpleReader) .processor(compositeItemProcessor()) .writer(list -> list.forEach(System.out::println)) .build(); } // CompositeItemProcessor组合多种中间处理器 private CompositeItemProcessor compositeItemProcessor() { CompositeItemProcessor processor = new CompositeItemProcessor<>(); List> processors = Arrays.asList(testDataFilterItemProcessor, testDataTransformItemPorcessor); // 代理两个processor processor.setDelegates(processors); return processor; } } ================================================ FILE: 70.spring-batch-itemprocessor/src/main/java/cc/mrbird/batch/entity/job/TestDataFilterItemProcessorDemo.java ================================================ package cc.mrbird.batch.entity.job; import cc.mrbird.batch.entity.TestData; import cc.mrbird.batch.processor.TestDataFilterItemProcessor; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; import org.springframework.batch.item.support.ListItemReader; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; /** * @author MrBird */ @Component public class TestDataFilterItemProcessorDemo { @Autowired private JobBuilderFactory jobBuilderFactory; @Autowired private StepBuilderFactory stepBuilderFactory; @Autowired private ListItemReader simpleReader; @Autowired private TestDataFilterItemProcessor testDataFilterItemProcessor; @Bean public Job testDataFilterItemProcessorJob() { return jobBuilderFactory.get("testDataFilterItemProcessorJob") .start(step()) .build(); } private Step step() { return stepBuilderFactory.get("step") .chunk(2) .reader(simpleReader) .processor(testDataFilterItemProcessor) .writer(list -> list.forEach(System.out::println)) .build(); } } ================================================ FILE: 70.spring-batch-itemprocessor/src/main/java/cc/mrbird/batch/entity/job/TestDataTransformItemPorcessorDemo.java ================================================ package cc.mrbird.batch.entity.job; import cc.mrbird.batch.entity.TestData; import cc.mrbird.batch.processor.TestDataFilterItemProcessor; import cc.mrbird.batch.processor.TestDataTransformItemPorcessor; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; import org.springframework.batch.item.support.ListItemReader; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; /** * @author MrBird */ @Component public class TestDataTransformItemPorcessorDemo { @Autowired private JobBuilderFactory jobBuilderFactory; @Autowired private StepBuilderFactory stepBuilderFactory; @Autowired private ListItemReader simpleReader; @Autowired private TestDataTransformItemPorcessor testDataTransformItemPorcessor; @Bean public Job testDataTransformItemPorcessorJob() { return jobBuilderFactory.get("testDataTransformItemPorcessorJob") .start(step()) .build(); } private Step step() { return stepBuilderFactory.get("step") .chunk(2) .reader(simpleReader) .processor(testDataTransformItemPorcessor) .writer(list -> list.forEach(System.out::println)) .build(); } } ================================================ FILE: 70.spring-batch-itemprocessor/src/main/java/cc/mrbird/batch/entity/job/ValidatingItemProcessorDemo.java ================================================ package cc.mrbird.batch.entity.job; import cc.mrbird.batch.entity.TestData; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; import org.springframework.batch.item.support.ListItemReader; import org.springframework.batch.item.validator.ValidatingItemProcessor; import org.springframework.batch.item.validator.ValidationException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; /** * @author MrBird */ @Component public class ValidatingItemProcessorDemo { @Autowired private JobBuilderFactory jobBuilderFactory; @Autowired private StepBuilderFactory stepBuilderFactory; @Autowired private ListItemReader simpleReader; @Bean public Job validatingItemProcessorJob() { return jobBuilderFactory.get("validatingItemProcessorJob") .start(step()) .build(); } private Step step() { return stepBuilderFactory.get("step") .chunk(2) .reader(simpleReader) .processor(validatingItemProcessor()) .writer(list -> list.forEach(System.out::println)) .build(); } private ValidatingItemProcessor validatingItemProcessor() { ValidatingItemProcessor processor = new ValidatingItemProcessor<>(); processor.setValidator(value -> { // 对每一条数据进行校验 if ("".equals(value.getField3())) { // 如果field3的值为空串,则抛异常 throw new ValidationException("field3的值不合法"); } }); return processor; } } ================================================ FILE: 70.spring-batch-itemprocessor/src/main/java/cc/mrbird/batch/entity/reader/ItemReaderConfigure.java ================================================ package cc.mrbird.batch.entity.reader; import cc.mrbird.batch.entity.TestData; import org.springframework.batch.item.support.ListItemReader; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.ArrayList; import java.util.List; /** * @author MrBird */ @Configuration public class ItemReaderConfigure { @Bean public ListItemReader simpleReader() { List data = new ArrayList<>(); TestData testData1 = new TestData(); testData1.setId(1); testData1.setField1("11"); testData1.setField2("12"); testData1.setField3("13"); data.add(testData1); TestData testData2 = new TestData(); testData2.setId(2); testData2.setField1("21"); testData2.setField2("22"); testData2.setField3("23"); data.add(testData2); TestData testData3 = new TestData(); testData3.setId(3); testData3.setField1("31"); testData3.setField2("32"); testData3.setField3(""); data.add(testData3); return new ListItemReader<>(data); } } ================================================ FILE: 70.spring-batch-itemprocessor/src/main/java/cc/mrbird/batch/processor/TestDataFilterItemProcessor.java ================================================ package cc.mrbird.batch.processor; import cc.mrbird.batch.entity.TestData; import org.springframework.batch.item.ItemProcessor; import org.springframework.stereotype.Component; /** * @author MrBird */ @Component public class TestDataFilterItemProcessor implements ItemProcessor { @Override public TestData process(TestData item) { // 返回null,会过滤掉这条数据 return "".equals(item.getField3()) ? null : item; } } ================================================ FILE: 70.spring-batch-itemprocessor/src/main/java/cc/mrbird/batch/processor/TestDataTransformItemPorcessor.java ================================================ package cc.mrbird.batch.processor; import cc.mrbird.batch.entity.TestData; import org.springframework.batch.item.ItemProcessor; import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Component; /** * @author MrBird */ @Component public class TestDataTransformItemPorcessor implements ItemProcessor { @Override public TestData process(TestData item) { // field1值拼接 hello item.setField1(item.getField1() + " hello"); return item; } } ================================================ FILE: 70.spring-batch-itemprocessor/src/main/resources/application.yml ================================================ spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://127.0.0.1:3306/springbatch username: root password: 123456 ================================================ FILE: 71.spring-batch-listener/pom.xml ================================================ 4.0.0 org.springframework.boot spring-boot-starter-parent 2.2.5.RELEASE cc.mrbird spring-batch-listener 0.0.1-SNAPSHOT spring-batch-listener Demo project for Spring Boot 1.8 org.springframework.boot spring-boot-starter-batch mysql mysql-connector-java org.springframework.boot spring-boot-starter-jdbc org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 71.spring-batch-listener/src/main/java/cc/mrbird/batch/SpringBatchListenerApplication.java ================================================ package cc.mrbird.batch; import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication @EnableBatchProcessing public class SpringBatchListenerApplication { public static void main(String[] args) { SpringApplication.run(SpringBatchListenerApplication.class, args); } } ================================================ FILE: 71.spring-batch-listener/src/main/java/cc/mrbird/batch/job/CompositeJobExecutionListenerJobDemo.java ================================================ package cc.mrbird.batch.job; import org.springframework.batch.core.Job; import org.springframework.batch.core.JobExecution; import org.springframework.batch.core.JobExecutionListener; import org.springframework.batch.core.Step; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; import org.springframework.batch.core.listener.CompositeJobExecutionListener; import org.springframework.batch.repeat.RepeatStatus; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; import java.util.Arrays; /** * @author MrBird */ @Component public class CompositeJobExecutionListenerJobDemo { @Autowired private JobBuilderFactory jobBuilderFactory; @Autowired private StepBuilderFactory stepBuilderFactory; @Bean public Job compositeJobExecutionListenerJob() { return jobBuilderFactory.get("compositeJobExecutionListenerJob") .start(step()) .listener(compositeJobExecutionListener()) .build(); } private Step step() { return stepBuilderFactory.get("step") .tasklet((contribution, chunkContext) -> { System.out.println("执行步骤...."); return RepeatStatus.FINISHED; }).build(); } private CompositeJobExecutionListener compositeJobExecutionListener() { CompositeJobExecutionListener listener = new CompositeJobExecutionListener(); // 任务监听器1 JobExecutionListener jobExecutionListenerOne = new JobExecutionListener() { @Override public void beforeJob(JobExecution jobExecution) { System.out.println("任务监听器One,before job execute: " + jobExecution.getJobInstance().getJobName()); } @Override public void afterJob(JobExecution jobExecution) { System.out.println("任务监听器One,after job execute: " + jobExecution.getJobInstance().getJobName()); } }; // 任务监听器2 JobExecutionListener jobExecutionListenerTwo = new JobExecutionListener() { @Override public void beforeJob(JobExecution jobExecution) { System.out.println("任务监听器Two,before job execute: " + jobExecution.getJobInstance().getJobName()); } @Override public void afterJob(JobExecution jobExecution) { System.out.println("任务监听器Two,after job execute: " + jobExecution.getJobInstance().getJobName()); } }; // 聚合 listener.setListeners(Arrays.asList(jobExecutionListenerOne, jobExecutionListenerTwo)); return listener; } } ================================================ FILE: 71.spring-batch-listener/src/main/java/cc/mrbird/batch/job/ListenerTestJobDemo.java ================================================ package cc.mrbird.batch.job; import cc.mrbird.batch.listener.*; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; import org.springframework.batch.item.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; import java.util.Arrays; import java.util.Iterator; import java.util.List; /** * @author MrBird */ @Component public class ListenerTestJobDemo { @Autowired private JobBuilderFactory jobBuilderFactory; @Autowired private StepBuilderFactory stepBuilderFactory; @Autowired private MyJobExecutionListener myJobExecutionListener; @Autowired private MyStepExecutionListener myStepExecutionListener; @Autowired private MyChunkListener myChunkListener; @Autowired private MyItemReaderListener myItemReaderListener; @Autowired private MyItemProcessListener myItemProcessListener; @Autowired private MyItemWriterListener myItemWriterListener; @Bean public Job listenerTestJob() { return jobBuilderFactory.get("listenerTestJob") .start(step()) .listener(myJobExecutionListener) .build(); } private Step step() { return stepBuilderFactory.get("step") .listener(myStepExecutionListener) .chunk(2) .faultTolerant() .listener(myChunkListener) .reader(reader()) .listener(myItemReaderListener) .processor(processor()) .listener(myItemProcessListener) .writer(list -> list.forEach(System.out::println)) .listener(myItemWriterListener) .build(); } private ItemReader reader() { List data = Arrays.asList("java", "c++", "javascript", "python"); return new simpleReader(data); } private ItemProcessor processor() { return item -> item + " language"; } } class simpleReader implements ItemReader { private Iterator iterator; public simpleReader(List data) { this.iterator = data.iterator(); } @Override public String read() { return iterator.hasNext() ? iterator.next() : null; } } ================================================ FILE: 71.spring-batch-listener/src/main/java/cc/mrbird/batch/listener/MyChunkListener.java ================================================ package cc.mrbird.batch.listener; import org.springframework.batch.core.ChunkListener; import org.springframework.batch.core.scope.context.ChunkContext; import org.springframework.stereotype.Component; /** * @author MrBird */ @Component public class MyChunkListener implements ChunkListener { @Override public void beforeChunk(ChunkContext context) { System.out.println("before chunk: " + context.getStepContext().getStepName()); } @Override public void afterChunk(ChunkContext context) { System.out.println("after chunk: " + context.getStepContext().getStepName()); } @Override public void afterChunkError(ChunkContext context) { System.out.println("before chunk error: " + context.getStepContext().getStepName()); } } ================================================ FILE: 71.spring-batch-listener/src/main/java/cc/mrbird/batch/listener/MyItemProcessListener.java ================================================ package cc.mrbird.batch.listener; import org.springframework.batch.core.ItemProcessListener; import org.springframework.stereotype.Component; /** * @author MrBird */ @Component public class MyItemProcessListener implements ItemProcessListener { @Override public void beforeProcess(String item) { System.out.println("before process: " + item); } @Override public void afterProcess(String item, String result) { System.out.println("after process: " + item + " result: " + result); } @Override public void onProcessError(String item, Exception e) { System.out.println("on process error: " + item + " , error message: " + e.getMessage()); } } ================================================ FILE: 71.spring-batch-listener/src/main/java/cc/mrbird/batch/listener/MyItemReaderListener.java ================================================ package cc.mrbird.batch.listener; import org.springframework.batch.core.ItemReadListener; import org.springframework.stereotype.Component; /** * @author MrBird */ @Component public class MyItemReaderListener implements ItemReadListener { @Override public void beforeRead() { System.out.println("before read"); } @Override public void afterRead(String item) { System.out.println("after read: " + item); } @Override public void onReadError(Exception ex) { System.out.println("on read error: " + ex.getMessage()); } } ================================================ FILE: 71.spring-batch-listener/src/main/java/cc/mrbird/batch/listener/MyItemWriterListener.java ================================================ package cc.mrbird.batch.listener; import org.springframework.batch.core.ItemWriteListener; import org.springframework.stereotype.Component; import java.util.List; /** * @author MrBird */ @Component public class MyItemWriterListener implements ItemWriteListener { @Override public void beforeWrite(List items) { System.out.println("before write: " + items); } @Override public void afterWrite(List items) { System.out.println("after write: " + items); } @Override public void onWriteError(Exception exception, List items) { System.out.println("on write error: " + items + " , error message: " + exception.getMessage()); } } ================================================ FILE: 71.spring-batch-listener/src/main/java/cc/mrbird/batch/listener/MyJobExecutionListener.java ================================================ package cc.mrbird.batch.listener; import org.springframework.batch.core.JobExecution; import org.springframework.batch.core.JobExecutionListener; import org.springframework.stereotype.Component; /** * @author MrBird */ @Component public class MyJobExecutionListener implements JobExecutionListener { @Override public void beforeJob(JobExecution jobExecution) { System.out.println("before job execute: " + jobExecution.getJobInstance().getJobName()); } @Override public void afterJob(JobExecution jobExecution) { System.out.println("after job execute: " + jobExecution.getJobInstance().getJobName()); } } ================================================ FILE: 71.spring-batch-listener/src/main/java/cc/mrbird/batch/listener/MyStepExecutionListener.java ================================================ package cc.mrbird.batch.listener; import org.springframework.batch.core.StepExecution; import org.springframework.batch.core.annotation.AfterStep; import org.springframework.batch.core.annotation.BeforeStep; import org.springframework.stereotype.Component; /** * @author MrBird */ @Component public class MyStepExecutionListener { @BeforeStep public void breforeStep(StepExecution stepExecution) { System.out.println("before step execute: " + stepExecution.getStepName()); } @AfterStep public void afterStep(StepExecution stepExecution) { System.out.println("after step execute: " + stepExecution.getStepName()); } } ================================================ FILE: 71.spring-batch-listener/src/main/resources/application.yml ================================================ spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://127.0.0.1:3306/springbatch username: root password: 123456 ================================================ FILE: 72.spring-batch-exception/pom.xml ================================================ 4.0.0 org.springframework.boot spring-boot-starter-parent 2.2.5.RELEASE cc.mrbird spring-batch-exception 0.0.1-SNAPSHOT spring-batch-exception Demo project for Spring Boot 1.8 org.springframework.boot spring-boot-starter-batch mysql mysql-connector-java org.springframework.boot spring-boot-starter-jdbc org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 72.spring-batch-exception/src/main/java/cc/mrbird/batch/SpringBatchExceptionApplication.java ================================================ package cc.mrbird.batch; import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication @EnableBatchProcessing public class SpringBatchExceptionApplication { public static void main(String[] args) { SpringApplication.run(SpringBatchExceptionApplication.class, args); } } ================================================ FILE: 72.spring-batch-exception/src/main/java/cc/mrbird/batch/exception/MyJobExecutionException.java ================================================ package cc.mrbird.batch.exception; /** * @author MrBird */ public class MyJobExecutionException extends Exception{ private static final long serialVersionUID = 7168487913507656106L; public MyJobExecutionException(String message) { super(message); } } ================================================ FILE: 72.spring-batch-exception/src/main/java/cc/mrbird/batch/job/DefaultExceptionJobDemo.java ================================================ package cc.mrbird.batch.job; import org.springframework.batch.core.Job; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; import org.springframework.batch.item.ExecutionContext; import org.springframework.batch.repeat.RepeatStatus; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; /** * @author MrBird */ @Component public class DefaultExceptionJobDemo { @Autowired private JobBuilderFactory jobBuilderFactory; @Autowired private StepBuilderFactory stepBuilderFactory; @Bean public Job defaultExceptionJob() { return jobBuilderFactory.get("defaultExceptionJob") .start( stepBuilderFactory.get("step") .tasklet((stepContribution, chunkContext) -> { // 获取执行上下文 ExecutionContext executionContext = chunkContext.getStepContext().getStepExecution().getExecutionContext(); if (executionContext.containsKey("success")) { System.out.println("任务执行成功"); return RepeatStatus.FINISHED; } else { String errorMessage = "处理任务过程发生异常"; System.out.println(errorMessage); executionContext.put("success", true); throw new RuntimeException(errorMessage); } }).build() ).build(); } } ================================================ FILE: 72.spring-batch-exception/src/main/java/cc/mrbird/batch/job/RestartJobDemo.java ================================================ package cc.mrbird.batch.job; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; import org.springframework.batch.item.support.ListItemReader; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.interceptor.DefaultTransactionAttribute; import java.util.ArrayList; import java.util.stream.IntStream; /** * @author MrBird */ @Component public class RestartJobDemo { @Autowired private JobBuilderFactory jobBuilderFactory; @Autowired private StepBuilderFactory stepBuilderFactory; @Bean public Job restartJob() { return jobBuilderFactory.get("restartJob") .start(step()) .build(); } private Step step() { return stepBuilderFactory.get("step") .chunk(2) .reader(listItemReader()) .writer(list -> list.forEach(System.out::println)) // .allowStartIfComplete(true) .startLimit(1) .build(); } private ListItemReader listItemReader() { ArrayList datas = new ArrayList<>(); IntStream.range(0, 5).forEach(i -> datas.add(String.valueOf(i))); return new ListItemReader<>(datas); } } ================================================ FILE: 72.spring-batch-exception/src/main/java/cc/mrbird/batch/job/RetryExceptionJobDemo.java ================================================ package cc.mrbird.batch.job; import cc.mrbird.batch.exception.MyJobExecutionException; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; import org.springframework.batch.item.ItemProcessor; import org.springframework.batch.item.support.ListItemReader; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.stream.IntStream; /** * @author MrBird */ @Component public class RetryExceptionJobDemo { @Autowired private JobBuilderFactory jobBuilderFactory; @Autowired private StepBuilderFactory stepBuilderFactory; @Bean public Job retryExceptionJob() { return jobBuilderFactory.get("retryExceptionJob") .start(step()) .build(); } private Step step() { return stepBuilderFactory.get("step") .chunk(2) .reader(listItemReader()) .processor(myProcessor()) .writer(list -> list.forEach(System.out::println)) .faultTolerant() // 配置错误容忍 .retry(MyJobExecutionException.class) // 配置重试的异常类型 .retryLimit(3) // 重试3次,三次过后还是异常的话,则任务会结束, // 异常的次数为reader,processor和writer中的总数,这里仅在processor里演示异常重试 .build(); } private ListItemReader listItemReader() { ArrayList datas = new ArrayList<>(); IntStream.range(0, 5).forEach(i -> datas.add(String.valueOf(i))); return new ListItemReader<>(datas); } private ItemProcessor myProcessor() { return new ItemProcessor() { private int count; @Override public String process(String item) throws Exception { System.out.println("当前处理的数据:" + item); if (count >= 2) { return item; } else { count++; throw new MyJobExecutionException("任务处理出错"); } } }; } } ================================================ FILE: 72.spring-batch-exception/src/main/java/cc/mrbird/batch/job/SkipExceptionJobDemo.java ================================================ package cc.mrbird.batch.job; import cc.mrbird.batch.exception.MyJobExecutionException; import cc.mrbird.batch.listener.MySkipListener; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; import org.springframework.batch.item.ItemProcessor; import org.springframework.batch.item.support.ListItemReader; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.stream.IntStream; /** * @author MrBird */ @Component public class SkipExceptionJobDemo { @Autowired private JobBuilderFactory jobBuilderFactory; @Autowired private StepBuilderFactory stepBuilderFactory; @Autowired private MySkipListener mySkipListener; @Bean public Job skipExceptionJob() { return jobBuilderFactory.get("skipExceptionJob") .start(step()) .build(); } private Step step() { return stepBuilderFactory.get("step") .chunk(2) .reader(listItemReader()) .processor(myProcessor()) .writer(list -> list.forEach(System.out::println)) .faultTolerant() // 配置错误容忍 .skip(MyJobExecutionException.class) // 配置跳过的异常类型 .skipLimit(1) // 最多跳过1次,1次过后还是异常的话,则任务会结束, // 异常的次数为reader,processor和writer中的总数,这里仅在processor里演示异常跳过 .listener(mySkipListener) .build(); } private ListItemReader listItemReader() { ArrayList datas = new ArrayList<>(); IntStream.range(0, 5).forEach(i -> datas.add(String.valueOf(i))); return new ListItemReader<>(datas); } private ItemProcessor myProcessor() { return item -> { System.out.println("当前处理的数据:" + item); if ("2".equals(item)) { throw new MyJobExecutionException("任务处理出错"); } else { return item; } }; } } ================================================ FILE: 72.spring-batch-exception/src/main/java/cc/mrbird/batch/job/TransactionJobDemo.java ================================================ package cc.mrbird.batch.job; import cc.mrbird.batch.exception.MyJobExecutionException; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; import org.springframework.batch.item.ItemProcessor; import org.springframework.batch.item.support.ListItemReader; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.interceptor.DefaultTransactionAttribute; import java.util.ArrayList; import java.util.stream.IntStream; /** * @author MrBird */ @Component public class TransactionJobDemo { @Autowired private JobBuilderFactory jobBuilderFactory; @Autowired private StepBuilderFactory stepBuilderFactory; @Bean public Job transactionJob() { return jobBuilderFactory.get("transactionJob") .start(step()) .build(); } private Step step() { DefaultTransactionAttribute attribute = new DefaultTransactionAttribute(); attribute.setPropagationBehavior(Propagation.REQUIRED.value()); attribute.setIsolationLevel(Isolation.DEFAULT.value()); attribute.setTimeout(30); return stepBuilderFactory.get("step") .chunk(2) .reader(listItemReader()) .writer(list -> list.forEach(System.out::println)) .readerIsTransactionalQueue() .transactionAttribute(attribute) .build(); } private ListItemReader listItemReader() { ArrayList datas = new ArrayList<>(); IntStream.range(0, 5).forEach(i -> datas.add(String.valueOf(i))); return new ListItemReader<>(datas); } } ================================================ FILE: 72.spring-batch-exception/src/main/java/cc/mrbird/batch/listener/MySkipListener.java ================================================ package cc.mrbird.batch.listener; import org.springframework.batch.core.SkipListener; import org.springframework.stereotype.Component; /** * @author MrBird */ @Component public class MySkipListener implements SkipListener { @Override public void onSkipInRead(Throwable t) { System.out.println("在读取数据的时候遇到异常并跳过,异常:" + t.getMessage()); } @Override public void onSkipInWrite(String item, Throwable t) { System.out.println("在输出数据的时候遇到异常并跳过,待输出数据:" + item + ",异常:" + t.getMessage()); } @Override public void onSkipInProcess(String item, Throwable t) { System.out.println("在处理数据的时候遇到异常并跳过,待输出数据:" + item + ",异常:" + t.getMessage()); } } ================================================ FILE: 72.spring-batch-exception/src/main/resources/application.yml ================================================ spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://127.0.0.1:3306/springbatch username: root password: 123456 ================================================ FILE: 73.spring-batch-launcher/pom.xml ================================================ 4.0.0 org.springframework.boot spring-boot-starter-parent 2.2.5.RELEASE cc.mrbird spring-batch-launcher 0.0.1-SNAPSHOT spring-batch-launcher Demo project for Spring Boot 1.8 org.springframework.boot spring-boot-starter-batch org.springframework.boot spring-boot-starter-jdbc org.springframework.boot spring-boot-starter-web mysql mysql-connector-java runtime org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 73.spring-batch-launcher/src/main/java/cc/mrbird/batch/SpringBatchLauncherApplication.java ================================================ package cc.mrbird.batch; import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication @EnableBatchProcessing public class SpringBatchLauncherApplication { public static void main(String[] args) { SpringApplication.run(SpringBatchLauncherApplication.class, args); } } ================================================ FILE: 73.spring-batch-launcher/src/main/java/cc/mrbird/batch/configure/JobConfigure.java ================================================ package cc.mrbird.batch.configure; import org.springframework.batch.core.configuration.JobRegistry; import org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * @author MrBird */ @Configuration public class JobConfigure { /** * 注册JobRegistryBeanPostProcessor bean * 用于将任务名称和实际的任务关联起来 */ @Bean public JobRegistryBeanPostProcessor processor(JobRegistry jobRegistry, ApplicationContext applicationContext) { JobRegistryBeanPostProcessor postProcessor = new JobRegistryBeanPostProcessor(); postProcessor.setJobRegistry(jobRegistry); postProcessor.setBeanFactory(applicationContext.getAutowireCapableBeanFactory()); return postProcessor; } } ================================================ FILE: 73.spring-batch-launcher/src/main/java/cc/mrbird/batch/controller/JobController.java ================================================ package cc.mrbird.batch.controller; import org.springframework.batch.core.Job; import org.springframework.batch.core.JobParameters; import org.springframework.batch.core.JobParametersBuilder; import org.springframework.batch.core.launch.JobLauncher; import org.springframework.batch.core.launch.JobOperator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * @author MrBird */ @RestController @RequestMapping("job") public class JobController { @Autowired private Job job; @Autowired private JobLauncher jobLauncher; @Autowired private JobOperator jobOperator; @GetMapping("launcher/{message}") public String launcher(@PathVariable String message) throws Exception { JobParameters parameters = new JobParametersBuilder() .addString("message", message) .toJobParameters(); // 将参数传递给任务 jobLauncher.run(job, parameters); return "success"; } @GetMapping("operator/{message}") public String operator(@PathVariable String message) throws Exception { // 传递任务名称,参数使用 kv方式 jobOperator.start("job", "message=" + message); return "success"; } } ================================================ FILE: 73.spring-batch-launcher/src/main/java/cc/mrbird/batch/job/MyJob.java ================================================ package cc.mrbird.batch.job; import org.springframework.batch.core.*; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; import org.springframework.batch.repeat.RepeatStatus; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; import java.util.Map; /** * @author MrBird */ @Component public class MyJob{ @Autowired private JobBuilderFactory jobBuilderFactory; @Autowired private StepBuilderFactory stepBuilderFactory; @Bean public Job job(){ return jobBuilderFactory.get("job") .start(step()) .build(); } private Step step(){ return stepBuilderFactory.get("step") .tasklet((stepContribution, chunkContext) -> { StepExecution stepExecution = chunkContext.getStepContext().getStepExecution(); Map parameters = stepExecution.getJobParameters().getParameters(); System.out.println(parameters.get("message").getValue()); return RepeatStatus.FINISHED; }) .listener(this) .build(); } } ================================================ FILE: 73.spring-batch-launcher/src/main/resources/application.yml ================================================ spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/springbatch?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2b8 username: root password: 123456 batch: job: enabled: false ================================================ FILE: 74.spring-cloud-alibaba-nacos-register/consumer/pom.xml ================================================ 4.0.0 cc.mrbird spring-cloud-alibaba-nacos-register 1.0-SNAPSHOT ../pom.xml consumer consumer 服务消费端 org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 74.spring-cloud-alibaba-nacos-register/consumer/src/main/java/cc/mrbird/consumer/ConsumerApplication.java ================================================ package cc.mrbird.consumer; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class ConsumerApplication { public static void main(String[] args) { SpringApplication.run(ConsumerApplication.class, args); } } ================================================ FILE: 74.spring-cloud-alibaba-nacos-register/consumer/src/main/java/cc/mrbird/consumer/configure/ConsumerConfigure.java ================================================ package cc.mrbird.consumer.configure; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate; /** * @author MrBird */ @Configuration public class ConsumerConfigure { @Bean public RestTemplate restTemplate() { return new RestTemplate(); } } ================================================ FILE: 74.spring-cloud-alibaba-nacos-register/consumer/src/main/java/cc/mrbird/consumer/controller/ConsumeController.java ================================================ package cc.mrbird.consumer.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; /** * @author MrBird */ @RestController @RequestMapping("consume") public class ConsumeController { @Autowired private LoadBalancerClient loadBalancerClient; @Autowired private RestTemplate restTemplate; @GetMapping("hello/{message}") public String hello(@PathVariable String message) { ServiceInstance serviceInstance = loadBalancerClient.choose("provider"); String path = String.format("http://%s:%s/provide/%s", serviceInstance.getHost(), serviceInstance.getPort(), message); String result = restTemplate.getForObject(path, String.class); return String.format("%s from %s %s", result, serviceInstance.getHost(), serviceInstance.getPort()); } } ================================================ FILE: 74.spring-cloud-alibaba-nacos-register/consumer/src/main/resources/application.yml ================================================ server: port: 9001 spring: application: name: consumer cloud: nacos: server-addr: localhost:8848 ================================================ FILE: 74.spring-cloud-alibaba-nacos-register/pom.xml ================================================ 4.0.0 cc.mrbird spring-cloud-alibaba-nacos-register 1.0-SNAPSHOT pom provider consumer org.springframework.boot spring-boot-starter-parent 2.2.3.RELEASE 1.8 Hoxton.SR3 2.2.0.RELEASE org.springframework.boot spring-boot-starter-web com.alibaba.cloud spring-cloud-alibaba-nacos-discovery org.springframework.cloud spring-cloud-dependencies ${spring-cloud.version} pom import com.alibaba.cloud spring-cloud-alibaba-dependencies ${com-alibaba-cloud.version} pom import ================================================ FILE: 74.spring-cloud-alibaba-nacos-register/provider/pom.xml ================================================ 4.0.0 cc.mrbird spring-cloud-alibaba-nacos-register 1.0-SNAPSHOT ../pom.xml provider provider 服务提供端 org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 74.spring-cloud-alibaba-nacos-register/provider/src/main/java/cc/mrbird/provider/ProviderApplication.java ================================================ package cc.mrbird.provider; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class ProviderApplication { public static void main(String[] args) { SpringApplication.run(ProviderApplication.class, args); } } ================================================ FILE: 74.spring-cloud-alibaba-nacos-register/provider/src/main/java/cc/mrbird/provider/controller/HelloController.java ================================================ package cc.mrbird.provider.controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * @author MrBird */ @RestController @RequestMapping("provide") public class HelloController { @GetMapping("{message}") public String hello(@PathVariable String message) { return String.format("hello %s", message); } } ================================================ FILE: 74.spring-cloud-alibaba-nacos-register/provider/src/main/resources/application.yml ================================================ server: port: 8001 spring: application: name: provider cloud: nacos: server-addr: localhost:8848 ================================================ FILE: 75.spring-cloud-alibaba-nacos-config/pom.xml ================================================ 4.0.0 org.springframework.boot spring-boot-starter-parent 2.2.5.RELEASE cc.mrbird spring-cloud-alibaba-nacos-config 0.0.1-SNAPSHOT spring-cloud-alibaba-nacos-config Demo project for Spring Boot 1.8 Hoxton.SR3 2.2.0.RELEASE org.springframework.boot spring-boot-starter-web com.alibaba.cloud spring-cloud-alibaba-nacos-config org.springframework.cloud spring-cloud-dependencies ${spring-cloud.version} pom import com.alibaba.cloud spring-cloud-alibaba-dependencies ${com-alibaba-cloud.version} pom import org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 75.spring-cloud-alibaba-nacos-config/src/main/java/cc/mrbird/nacos/SpringCloudAlibabaNacosConfigApplication.java ================================================ package cc.mrbird.nacos; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class SpringCloudAlibabaNacosConfigApplication { public static void main(String[] args) { SpringApplication.run(SpringCloudAlibabaNacosConfigApplication.class, args); } } ================================================ FILE: 75.spring-cloud-alibaba-nacos-config/src/main/java/cc/mrbird/nacos/controller/TestController.java ================================================ package cc.mrbird.nacos.controller; import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; /** * @author MrBird */ @RestController @RefreshScope public class TestController { @Value("${message:null}") private String message; @Value("${ext1:null}") private String ext1; @Value("${ext2:null}") private String ext2; @GetMapping("message") public String getMessage() { return this.message; } @GetMapping("multi") public String multiConfig() { return String.format("ext1: %s ext2: %s", ext1, ext2); } } ================================================ FILE: 75.spring-cloud-alibaba-nacos-config/src/main/resources/application.yml ================================================ server: port: 8080 spring: application: name: my-project ================================================ FILE: 75.spring-cloud-alibaba-nacos-config/src/main/resources/bootstrap.yml ================================================ spring: # profiles: # active: dev cloud: nacos: config: server-addr: localhost:8848 # file-extension: yaml # prefix: febs # namespace: '2ef2186e-078c-4904-8643-ff5e90555456' # group: GROUP_A # extension-configs: # - dataId: ext-config-one.yaml # group: DEFAULT_GROUP # refresh: true # - dataId: ext-config-one.yaml # group: DEFAULT_GROUP # refresh: false shared-configs: ext-config-one.yaml,ext-config-two.yaml ================================================ FILE: 76.spring-boot-websocket-socketjs/pom.xml ================================================ 4.0.0 org.springframework.boot spring-boot-starter-parent 2.2.5.RELEASE cc.mrbird spring-boot-websocket-socketjs 0.0.1-SNAPSHOT spring-boot-websocket-socketjs Demo project for Spring Boot 1.8 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-websocket org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 76.spring-boot-websocket-socketjs/src/main/java/cc/mrbird/socket/SpringBootWebsocketSocketjsApplication.java ================================================ package cc.mrbird.socket; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class SpringBootWebsocketSocketjsApplication { public static void main(String[] args) { SpringApplication.run(SpringBootWebsocketSocketjsApplication.class, args); } } ================================================ FILE: 76.spring-boot-websocket-socketjs/src/main/java/cc/mrbird/socket/configure/WebSocketServerConfigure.java ================================================ package cc.mrbird.socket.configure; import cc.mrbird.socket.handler.MyStringWebSocketHandler; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.config.annotation.EnableWebSocket; import org.springframework.web.socket.config.annotation.WebSocketConfigurer; import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; /** * @author MrBird */ @Configuration @EnableWebSocket public class WebSocketServerConfigure implements WebSocketConfigurer { @Autowired private MyStringWebSocketHandler myStringWebSocketHandler; @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(myStringWebSocketHandler, "/connect").withSockJS(); } } ================================================ FILE: 76.spring-boot-websocket-socketjs/src/main/java/cc/mrbird/socket/handler/MyStringWebSocketHandler.java ================================================ package cc.mrbird.socket.handler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import org.springframework.web.socket.CloseStatus; import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.WebSocketSession; import org.springframework.web.socket.handler.TextWebSocketHandler; /** * @author MrBird */ @Component public class MyStringWebSocketHandler extends TextWebSocketHandler { private Logger log = LoggerFactory.getLogger(this.getClass()); @Override public void afterConnectionEstablished(WebSocketSession session) { log.info("和客户端建立连接"); } @Override public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception { session.close(CloseStatus.SERVER_ERROR); log.error("连接异常", exception); } @Override public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception { super.afterConnectionClosed(session, status); log.info("和客户端断开连接"); } @Override protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { // 获取到客户端发送过来的消息 String receiveMessage = message.getPayload(); log.info(receiveMessage); // 发送消息给客户端 session.sendMessage(new TextMessage(fakeAi(receiveMessage))); // 关闭连接 // session.close(CloseStatus.NORMAL); } private static String fakeAi(String input) { if (input == null || "".equals(input)) { return "你说什么?没听清︎"; } return input.replace('你', '我') .replace("吗", "") .replace('?', '!') .replace('?', '!'); } } ================================================ FILE: 76.spring-boot-websocket-socketjs/src/main/resources/application.properties ================================================ ================================================ FILE: 76.spring-boot-websocket-socketjs/src/main/resources/static/client.html ================================================ WebSocket客户端

聊天记录:

================================================ FILE: 77.spring-cloud-alibaba-sentinel-dashboard-guide/pom.xml ================================================ 4.0.0 org.springframework.boot spring-boot-starter-parent 2.2.5.RELEASE cc.mrbird spring-cloud-alibaba-sentinel-dashboard-guide 0.0.1-SNAPSHOT spring-cloud-alibaba-sentinel-dashboard-guide Demo project for Spring Boot 1.8 Hoxton.SR3 2.2.0.RELEASE org.springframework.boot spring-boot-starter-web com.alibaba.cloud spring-cloud-starter-alibaba-sentinel org.springframework.cloud spring-cloud-dependencies ${spring-cloud.version} pom import com.alibaba.cloud spring-cloud-alibaba-dependencies ${com-alibaba-cloud.version} pom import org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 77.spring-cloud-alibaba-sentinel-dashboard-guide/src/main/java/cc/mrbird/sentinel/SpringCloudAlibabaSentinelFlowControlApplication.java ================================================ package cc.mrbird.sentinel; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class SpringCloudAlibabaSentinelFlowControlApplication { public static void main(String[] args) { SpringApplication.run(SpringCloudAlibabaSentinelFlowControlApplication.class, args); } } ================================================ FILE: 77.spring-cloud-alibaba-sentinel-dashboard-guide/src/main/java/cc/mrbird/sentinel/controller/TestController.java ================================================ package cc.mrbird.sentinel.controller; import cc.mrbird.sentinel.service.HelloService; import com.alibaba.csp.sentinel.annotation.SentinelResource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; /** * @author MrBird */ @RestController public class TestController { private Logger log = LoggerFactory.getLogger(this.getClass()); @Autowired private HelloService helloService; @GetMapping("test1") public String test1() { throw new RuntimeException("服务异常"); // return "test1"; } @GetMapping("test2") public String test2() { return "test2 " + helloService.hello(); } @GetMapping("buy") @SentinelResource(value = "buy") public String buy(String goodName, Integer count) { return "买" + count + "份" + goodName; } } ================================================ FILE: 77.spring-cloud-alibaba-sentinel-dashboard-guide/src/main/java/cc/mrbird/sentinel/service/HelloService.java ================================================ package cc.mrbird.sentinel.service; import com.alibaba.csp.sentinel.annotation.SentinelResource; import org.springframework.stereotype.Service; /** * @author MrBird */ @Service public class HelloService { @SentinelResource("hello") public String hello() { return "hello"; } } ================================================ FILE: 77.spring-cloud-alibaba-sentinel-dashboard-guide/src/main/resources/application.yml ================================================ server: port: 8081 spring: application: name: my-project cloud: sentinel: transport: dashboard: localhost:8080 port: 8719 web-context-unify: false ================================================ FILE: 78.spring-cloud-alibaba-sentinelresource/consumer/pom.xml ================================================ 4.0.0 cc.mrbird spring-cloud-alibaba-sentinelresource 1.0-SNAPSHOT ../pom.xml consumer consumer 服务消费者 1.8 com.alibaba.cloud spring-cloud-starter-alibaba-sentinel org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 78.spring-cloud-alibaba-sentinelresource/consumer/src/main/java/cc/mrbird/consumer/ConsumerApplication.java ================================================ package cc.mrbird.consumer; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; @SpringBootApplication public class ConsumerApplication { public static void main(String[] args) { SpringApplication.run(ConsumerApplication.class, args); } @Bean @LoadBalanced public RestTemplate restTemplate(){ return new RestTemplate(); } } ================================================ FILE: 78.spring-cloud-alibaba-sentinelresource/consumer/src/main/resources/application.yml ================================================ server: port: 9091 spring: application: name: consumer cloud: nacos: server-addr: localhost:8001 sentinel: transport: dashboard: localhost:8080 port: 8719 ================================================ FILE: 78.spring-cloud-alibaba-sentinelresource/pom.xml ================================================ 4.0.0 cc.mrbird spring-cloud-alibaba-sentinelresource 1.0-SNAPSHOT pom org.springframework.boot spring-boot-starter-parent 2.2.3.RELEASE provider consumer 1.8 Hoxton.SR3 2.2.0.RELEASE org.springframework.boot spring-boot-starter-web com.alibaba.cloud spring-cloud-alibaba-nacos-discovery org.springframework.cloud spring-cloud-dependencies ${spring-cloud.version} pom import com.alibaba.cloud spring-cloud-alibaba-dependencies ${com-alibaba-cloud.version} pom import ================================================ FILE: 78.spring-cloud-alibaba-sentinelresource/provider/pom.xml ================================================ 4.0.0 cc.mrbird spring-cloud-alibaba-sentinelresource 1.0-SNAPSHOT ../pom.xml provider provider 服务提供者 1.8 org.springframework.boot spring-boot-maven-plugin ================================================ FILE: 78.spring-cloud-alibaba-sentinelresource/provider/src/main/java/cc/mrbird/provider/ProviderApplication.java ================================================ package cc.mrbird.provider; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class ProviderApplication { public static void main(String[] args) { SpringApplication.run(ProviderApplication.class, args); } } ================================================ FILE: 78.spring-cloud-alibaba-sentinelresource/provider/src/main/resources/application.yml ================================================ server: port: 8081 spring: application: name: provider cloud: nacos: server-addr: localhost:8001 ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2018 MrBird Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: readme.md ================================================ ## Spring 系列教程 该仓库为个人博客[https://mrbird.cc](https://mrbird.cc)中Spring系列源码,包含Spring Boot、Spring Boot & Shiro、Spring Cloud,Spring Boot & Spring Security & Spring Security OAuth2,如果该系列教程对您有帮助的话,还请点个star给予精神支持!🐤 ### Spring Boot教程 1. [开启Spring Boot](https://mrbird.cc/%E5%BC%80%E5%90%AFSpring-Boot.html) 2. [Spring Boot基础配置](https://mrbird.cc/Spring-Boot%20basic%20config.html) 3. [Spring Boot中使用MyBatis](https://mrbird.cc/Spring-Boot%20Mybatis.html) 4. [Spring Boot中使用JdbcTemplate](https://mrbird.cc/Spring-Boot%20JdbcTemplate.html) 5. [Spring Boot MyBatis配置Druid多数据源](https://mrbird.cc/Spring-Boot-MyBatis%20Druid.html) 6. [Spring Boot JdbcTemplate配置Druid多数据源](https://mrbird.cc/Spring-Boot-JdbcTemplate%20Druid.html) 7. [Spring Boot AOP记录用户操作日志](https://mrbird.cc/Spring-Boot-AOP%20log.html) 8. [Spring Boot中使用thymeleaf](https://mrbird.cc/Spring-Boot%E4%BD%BF%E7%94%A8thymeleaf.html) 9. [Spring Boot中使用Redis缓存数据](https://mrbird.cc/Spring-Boot%20cache.html) 10. [Spring Boot中使用Ehcache缓存数据](https://mrbird.cc/Spring-Boot%20cache.html) 11. [Spring Boot中的JSON技术](https://mrbird.cc/Spring-Boot%20JSON.html) 12. [Spring Boot中编写单元测试](https://mrbird.cc/Spring-Boot%20TESTing.html) 13. [Spring Boot整合Swagger2构建RESTful API](https://mrbird.cc/Spring-Boot-Swagger2-RESTful-API.html) 14. [使用Actuator监控Spring Boot应用](https://mrbird.cc/Acutator-Spring-Boot.html) 15. [使用Spring Boot发送邮件](https://mrbird.cc/Spring-Boot-Email.html) 16. [使用Spring Boot Admin监控服务](https://mrbird.cc/Spring-Boot-Admin.html) 17. [Spring Boot Devtools热部署](https://mrbird.cc/Spring-Boot-Devtools.html) 18. [Spring Boot logback日志配置](https://mrbird.cc/Spring-Boot-logback.html) 19. [Spring Boot项目打包成war包](https://mrbird.cc/Spring-Boot%20war.html) 20. [Linux下部署Spring Boot jar](https://mrbird.cc/Linux%20Spring-Boot-jar.html) 21. [Spring Boot中使用Jsoup防御XSS攻击](https://mrbird.cc/Jsoup%20XSS.html) 22. [Spring Boot异常处理](https://mrbird.cc/Spring-Boot-Exception.html) 23. [Spring Boot中使用过滤器和拦截器](https://mrbird.cc/Spring-Boot-Filter-Interceptor.html) 24. [Spring Boot整合MyBatis通用Mapper和PageHelper](https://mrbird.cc/MyBatis%20common%20Mapper%20PageHelper.html) 26. [深入学习Spring Boot自动装配](https://mrbird.cc/deepin-springboot-autoconfig.html) 27. [深入学习Spring Boot中的SpringApplication](https://mrbird.cc/deepin-springboot-application.html) 28. [Spring Boot配合Hibernate Validator参数校验](https://mrbird.cc/Spring-Boot-Hibernate-Validator-Params-Check.html) 29. [自定义Spring Boot 内容协商](https://mrbird.cc/Spring-Boot-Diy-Resolver.html) 30. [Spring Boot 中处理跨域](https://mrbird.cc/Spring-Boot-Deal-CORS.html) 31. [Spring Boot 中的异步调用](https://mrbird.cc/Spring-Boot-Async.html) 32. [Spring Boot 整合Kafka](https://mrbird.cc/Spring-Boot-Kafka.html) 33. [Spring Boot整合Mongo DB](https://mrbird.cc/Spring-Boot-Mongo-DB-CRUD.html) 34. [Spring Boot 2.0 WebFlux编程](https://mrbird.cc/Spring-Boot-2-0-WebFlux.html) 35. [Spring Boot WebFlux增删改查样例](https://mrbird.cc/Spring-Boot-WebFlux-CRUD.html) 36. [Spring Boot整合WebSocket](https://mrbird.cc/Spring-Boot整合WebSocket.html) ### Spring Boot & Shiro教程 1. [Spring Boot Shiro用户认证](https://mrbird.cc/Spring-Boot-shiro%20Authentication.html) 2. [Spring Boot Shiro Remember Me](https://mrbird.cc/Spring-Boot-Shiro%20Remember-Me.html) 3. [Spring Boot Shiro权限控制](https://mrbird.cc/Spring-Boot-Shiro%20Authorization.html) 4. [Spring Boot Shiro Redis](https://mrbird.cc/Spring-Boot-Shiro%20cache.html) 5. [Spring Boot Shiro Ehcache](https://mrbird.cc/Spring-Boot-Shiro%20cache.html) 6. [Spring Boot Thymeleaf中使用Shiro标签](https://mrbird.cc/Spring-Boot-Themeleaf%20Shiro%20tag.html) 7. [Spring Boot Shiro在线会话管理](https://mrbird.cc/Spring-Boot-Shiro%20session.html) 8. [Spring Boot Shiro整合JWT](https://github.com/wuyouzhuguli/SpringAll/tree/master/62.Spring-Boot-Shiro-JWT) ### Spring Boot & Security教程 1. [Spring Boot中开启Spring Security](https://mrbird.cc/Spring-Boot&Spring-Security.html) 2. [Spring Security自定义用户认证](https://mrbird.cc/Spring-Security-Authentication.html) 3. [Spring Security添加图形验证码](https://mrbird.cc/Spring-Security-ValidateCode.html) 4. [Spring Security添加记住我功能](https://mrbird.cc/Spring-Security-RememberMe.html) 5. [Spring Security短信验证码登录](https://mrbird.cc/Spring-Security-SmsCode.html) 6. [Spring Security Session管理](https://mrbird.cc/Spring-Security-Session-Manage.html) 7. [Spring Security退出登录](https://mrbird.cc/Spring-Security-logout.html) 8. [Spring Security权限控制](https://mrbird.cc/Spring-Security-Permission.html) 9. [Spring Security OAuth2入门](https://mrbird.cc/Spring-Security-OAuth2-Guide.html) 10. [Spring Security OAuth2自定义Token获取方式](https://mrbird.cc/Spring-Security-OAuth2-Customize.html) 11. [Spring Security OAuth2自定义令牌配置](https://mrbird.cc/Spring-Security-OAuth2-Token-Config.html) 12. [Spring Security OAuth2单点登录](https://mrbird.cc/Spring-Security-OAuth2-SSO.html) ### Spring Cloud教程 1. [初识Spring Cloud与微服务](https://mrbird.cc/Spring-Cloud%20and%20MicroService.html) 2. [Spring Cloud Eureka服务治理](https://mrbird.cc/Spring-Cloud-Eureka.html) 3. [Spring Cloud Ribbon客户端负载均衡](https://mrbird.cc/Spring-Cloud-Ribbon-LoadBalance.html) 4. [Spring Cloud Hystrix服务容错](https://mrbird.cc/Spring-Cloud-Hystrix-Circuit-Breaker.html) 5. [Spring Cloud Hystrix Dashboard仪表盘](https://mrbird.cc/Spring-Cloud-Hystrix-Dashboard.html) 6. [Spring Cloud Hystrix Dashboard仪表盘 & RabbitMQ](https://mrbird.cc/Spring-Cloud-Hystrix-Dashboard.html) 7. [Spring Cloud Feign 声明式服务调用](https://mrbird.cc/Spring-Cloud-Feign.html) 8. [Spring Cloud Zuul服务网关](https://mrbird.cc/Spring-Cloud-Zuul-Router.html) 9. [Spring Cloud Config统一配置管理](https://mrbird.cc/Spring-Cloud-Config.html) 10. [使用Spring Cloud Bus刷新配置](https://mrbird.cc/Spring-Cloud-Bus.html) 11. [使用Spring Cloud Sleuth跟踪微服务](https://mrbird.cc/Spring-Cloud-sleuth.html) 12. [Spring Cloud Consul服务治理](https://mrbird.cc/Spring-Cloud-Consul.html) 13. [Spring Cloud Alibaba Nacos注册中心](https://mrbird.cc/Spring-Cloud-Alibaba-Nacos注册中心.html) 14. [Spring Cloud Alibaba Nacos配置中心](https://mrbird.cc/Spring-Cloud-Alibaba-Nacos配置中心.html) 15. [Spring Cloud Alibaba Sentinel控制台详解](https://mrbird.cc/Sentinel控制台详解.html) 16. [Spring Cloud Alibaba Sentinel @SentinelResource](https://mrbird.cc/Spring-Cloud-Alibaba-Sentinel-SentinelResource.html) ### Spring Boot && Dubbo教程 1. [Spring Boot整合Dubbo&Zookeeper](https://mrbird.cc/Spring-Boot-Dubbo-Zookeeper.html) 2. [监控Dubbo服务](https://mrbird.cc/dubbo-mointor.html) 3. [Dubbo的高可用](https://mrbird.cc/Dubbo-High-Availability.html) ### Spring Boot && Spring Batch教程 1. [Spring Batch入门](https://mrbird.cc/Spring-Batch入门.html) 2. [Spring Batch读取数据](https://mrbird.cc/Spring-Batch读取数据.html) 3. [Spring Batch输出数据](https://mrbird.cc/Spring-Batch输出数据.html) 4. [Spring Batch处理数据](https://mrbird.cc/Spring-Batch处理数据.html) 5. [Spring Batch监听器](https://mrbird.cc/Spring-Batch监听器.html) 6. [Spring Batch异常处理](https://mrbird.cc/Spring-Batch异常处理.html) 7. [Spring Batch任务调度](https://mrbird.cc/Spring-Batch作业调度.html) ## Spring 1. [深入学习Spring组件注册](https://mrbird.cc/Spring-Bean-Regist.html) 2. [深入学习Spring Bean生命周期](https://mrbird.cc/Spring-Bean-Lifecycle.html) 3. [深入理解Spring BeanPostProcessor & InstantiationAwareBeanPostProcessor](https://mrbird.cc/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3Spring-BeanPostProcessor-InstantiationAwareBeanPostProcessor.html) 4. [深入理解BeanFactoryPostProcessor & BeanDefinitionRegistryPostProcessor](https://mrbird.cc/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3BeanFactoryPostProcessor-BeanDefinitionRegistryPostProcessor.html) 5. [深入理解Spring AOP原理](https://mrbird.cc/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3Spring-AOP%E5%8E%9F%E7%90%86.html) 6. [Spring声明式事务原理](https://mrbird.cc/Spring%E5%A3%B0%E6%98%8E%E5%BC%8F%E4%BA%8B%E5%8A%A1%E5%8E%9F%E7%90%86.html) 7. [深入理解Spring事件发布与监听](https://mrbird.cc/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3Spring%E4%BA%8B%E4%BB%B6%E5%8F%91%E5%B8%83%E4%B8%8E%E7%9B%91%E5%90%AC.html) 8. [深入理解Spring循环依赖](https://mrbird.cc/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3Spring%E5%BE%AA%E7%8E%AF%E4%BE%9D%E8%B5%96.html) 持续更新中...