- 接口校验与pojo使用: 为了更好的利用
Spring Validator能力,按照业务领域建立pojo对象,pojo对象可能对应到多张数据库表;打破原来按照表建立pojo不能跨表操作的问题。 - 包组织方式: 各个业务包创建自己的controller、pojo、mybatis的mapper文件,每个业务包互相独立,不允许做横向调用,公共模块做抽象组装,做接口调用。
- mybatis调用方式: 为了减少接口编写工作,采用
SqlSession调用mapper接口的方式进行mybatis调用操作,mybatis的mapper.xml放置到各个业务包中。 - url规范命名: 为了便于nginx对后台接口做统一分发,在
application.yml里配置server.servlet.context-path属性为/api,所有请求默认带api前缀。 - 依赖Jackson配置POJO的Java命名规范和HTTP命名规范转换:
application.yml中配置spring.jackson.property-naming-strategy的属性为SNAKE_CASE,将Java属性的驼峰命名转换为http的标准下划线命名。 - 配置文件属性自动转换 使用Duration配置yml文件,允许设置时间单位或者数据单位。参考:Spring Boot官方手册4.2.8 Properties Conversion
- 配置样例参考配置文件
application.yml的jwt.validtiy属性jwt: # 24 hours validtiy: 24h
- 代码样例参考
JwtTokenPrivider的validtiyInMs属性@Value("${jwt.validtiy}") @DurationUnit(ChronoUnit.MILLIS) private Duration validityInMs;
- 配置样例参考配置文件
spring-jwt-example/ * 工程目录名,可以根据实际项目情况进行修改
|- resources
|- application.yml * 主配置文件,包含激活配置文件,jackson,servlet,jwt,日志配置等
|- application-dev.yml * 数据库配置
|- application-druid.xml * alibaba druid数据库连接池配置
|- application-mybatis.xml * mybatis配置,包含pagehelper配置
|- log4j2.xml * log4j2配置文件,默认打开console配置,可以配置异步输出;打印SQL的日志级别可以配置好
|- src/main/java
|- Body.java * controller返回org.springframework.http.ResponseEntity,Body是ResponseEntity的数据结构体,兼容@Valid返回的数据结构
|- SpringJwtExampleApplication.java * 启动类,根据项目情况进行修改
|- examples.spring.project * 源码包结构,根据实际项目进行重修改
|- config * 框架类的各种配置
|- CorsConfig.java * 跨域请求(Cross-Origin Resource Sharing)配置,已经配置成允许所有请求所有参数
|- WebSecurityConfig.java * JWT安全配置,有需要排除不做登录请求过滤的uri在这里面配置
|- exception
|- CustomExceptionHandlerjava * 使用@ControllerAdvice处理所有Controller抛出的异常并返回给前端,避免前端收到500错误页面
|- security
JwtUserDetailsService.java * 查询数据库进行登录验证,每次接口请求都会访问对应的类,如果对性能有要求,可以对登录校验加缓存
|- jwt
|- InvalidJwtAuthenticationException.java * JWT验证自定义异常类
|- JwtAuthenticationEntryPoint.java * JWT登录失败时调用的类
|- JwtSecurityConfigurer.java * 配置AuthenticationEntryPoint和JwtTokenAuthenticationFilter的类
|- JwtTokenAuthenticationFilter.java * JWT过滤器,验证每次请求的Token是否有效
|- JwtTokenProvider.java * JwtToken计算工具类
|- users
|- mapper * mybatis文件夹,mybatis mapper文件必须在这里才会被自动扫描到,在application-mybatis.xml文件中配置
|- Login.xml * 登录mybatis mapper文件
|- User.xml * 用户管理mybatis mapper文件
|- AuthenticationController.java * 登录验证,刷新token,获取当前用户的controller类
|- UserController.java * 用户管理,根据项目实际情况的进行修改
|- UserPojo.java * 用户管理模块配套的传值对象,增加了@Valid注解,启用校验,校验错误提示会返回给前端。根据项目实际情况修改字段属性
|- model1 * 样例模块,根据实际的情况进行命名编写,每个业务功能模块一个独立的包
|- mapper * 样例模块对应的mybatis mapper文件
|- Model1.xml * 样例mybatis mapper文件
|- Model1Controller.java * 样例controller类
|- Model1Pojo.java * 样例pojo类
|- src/test/java * 测试用例存放文件夹
|- examples.spring.project * 测试用例包,保持和源码包相同
|- model1
|- model1.http * model1所有接口的IDEA http client测试用例(测试脚本可以使用JUnit/Postman测试脚本/IDEA http client三者中的任意一种)
|- passwdtools
|- PasswordTools.java * 生成密码的工具类,默认使用bcrypt加密方式
|- users
|- users.http * users模块的测试用例
|- .gitignore * git提交忽略文件的配置项
|- pom.xml * pom配置。当前jwt依赖jsonwebtoken.jjwt
-
请求header
无
-
请求参数
| 参数名 | 参数值 | 说明 |
|---|---|---|
| user_name | admin | 登录账号 |
| password | 123456 | 登录密码 |
- 请求示例
curl -d "user_name=admin&password=123456" http://localhost:8080/api/authenticate- 响应参数
| 参数名 | 说明 |
|---|---|
| status | 响应状态,遵循w3c http code命名规约,200表示正常 |
| message | 响应值中文描述,可用于提示用户 |
| data | 响应数据结构,封装返回的业务数据结构 |
- data响应参数
| 参数名 | 说明 |
|---|---|
| user_name | 登录用户名 |
| token_expiration | token过期时间,需要在过期前调用refresh_token刷新token |
| token | token本身,注意此token没有包含Bearer 前缀,设置到http header时需要增加Bearer 前缀 |
- 响应示例
{
"status": 200,
"message": "登录成功",
"data": {
"user_name": "admin",
"token_expiration": "2020-04-14 14:31:42",
"token": "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsInJvbGVzIjpbXSwiaWF0IjoxNTg2ODQ1ODk3LCJleHAiOjE1ODY4NDU5MDJ9.-JiaVq4HlcIceojaa2SxgpZYA_MqhHezvAganke7OyA"
}
}- 请求Header
| 参数名 | 参数值 | 说明 |
|---|---|---|
| Accept | application/json | |
| Authorization | Bearer [token] | [token]填写登录获得的实际值 |
-
请求Body
无
-
请求示例
无
-
响应参数
参考登录验证接口
-
响应示例
参考登录验证接口
通过还在有效期的token,获取当前的用户信息,如果token已经失效,接口返回http code 403。
- 请求Header
| 参数名 | 参数值 | 说明 |
|---|---|---|
| Accept | application/json | |
| Authorization | Bearer [token] | [token]填写登录获得的实际值 |
-
请求Body
无
-
请求示例
无
-
响应参数
| 参数名 | 说明 |
|---|---|
| status | 响应状态,遵循w3c http code命名规约,200表示正常 |
| message | 响应值中文描述,可用于提示用户 |
| data | 响应数据结构,封装返回的业务数据结构 |
- data响应参数
| 参数名 | 说明 |
|---|---|
| username | 登录用户名(遵循SpringSecurity的UserDetail的命名规范,没有下划线分隔) |
| nickname | 用户昵称(遵循SpringSecurity的UserDetail的命名规范,没有下划线分隔) |
| account_non_expired | 账号非过期标识 |
| account_non_locked | 账号非锁定标识 |
| credentials_non_expired | 密码过期标识(不是token过期标识) |
| enabled | 账号是否启用 |
- 响应示例
{
"status": 200,
"message": "成功获取当前用户信息",
"data": {
"username": "admin",
"nickname": "系统管理员",
"account_non_expired": true,
"account_non_locked": true,
"credentials_non_expired": true,
"enabled": true
}
}SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for login_user
-- ----------------------------
DROP TABLE IF EXISTS `login_user`;
CREATE TABLE `login_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_name` varchar(50) DEFAULT NULL COMMENT '登录用户名',
`nick_name` varchar(200) DEFAULT NULL COMMENT '用户昵称',
`bcrypt_passwd` char(68) DEFAULT NULL COMMENT '加密密码',
`status` char(1) DEFAULT 'Y' COMMENT '用户状态\nY:正常 \nL:锁定\nD:逻辑删除',
`create_date` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '账号创建日期',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `idx_user_name` (`user_name`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COMMENT='用户登录信息表';
-- ----------------------------
-- Records of login_user
-- ----------------------------
BEGIN;
-- 当前默认密码是123456
INSERT INTO `login_user` VALUES (1, 'admin', '系统管理员', '{bcrypt}$2a$10$XMj0iNiUZNf5Dec5QL4.WOVa92tSY6xcRH6SjY.LajLZvVMVxb8Vy', 'Y', '2020-03-22 00:36:54', '2020-03-22 20:20:34');
COMMIT;
SET FOREIGN_KEY_CHECKS = 1;调用PasswordTools可以生成密码,填入数据库即可
- 在
/etc/systemd/system目录下配置spring-jw-example.service文件
[Unit]
Description=spring-jwt-example
After=syslog.target
[Service]
User=myapp
ExecStart=/var/spring-jwt-example/spring-jwt-example.1.0.0.RELEASE.jar /var/spring-jwt-example/config
SuccessExitStatus=143
[Install]
WantedBy=multi-user.target- 配置成自动启动
systemctl enable spring-jw-example.service- 启动服务
systemctl start spring-jw-example.service