Spring Boot +JWT +MybatisPlus,使用Token登录详细教程,附源码!
一、新建Spring Boot项目
1.File→New→Module
2.点击下一步
3.写完这些,点击下一步
4.选择插件
5.选择项目地址,选择完成后点击Finish
二
1…创建完成后,修改pom.xml文件,添加以下依赖
<!-- MybatisPlus 核心库 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.2.0</version>
</dependency>
<!-- StringUtilS工具 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.5</version>
</dependency>
<!-- JSON工具 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.45</version>
</dependency>
<!-- JWT依赖 -->
<!-- https://mvnrepository.com/artifact/com.auth0/java-jwt -->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.8.3</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
2.修改配置文件application.properties名称为application.yml,并创建新文件application-dev.yml
3.application.yml配置
spring:
profiles:
active: dev
4.application-dev.yml配置
server:
port: 9099
spring:
application:
name: demo
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/service_data?characterEncoding=utf-8&userUnicode=true&serverTimezone=Asia/Shanghai&useSSL=false
username: root
password: root
hikari:
minimum-idle: 3
maximum-pool-size: 5
max-lifetime: 0
jackson:
time-zone: GMT+8
date-format: yyyy-MM-dd HH:mm:ss
default-property-inclusion: non_null
servlet:
multipart:
max-file-size: 1024MB
max-request-size: 2048MB
#thymeleaf的配置
thymeleaf:
cache: false
enabled: true
#配置mybatisplus
mybatis-plus:
mapper-locations: classpath*:mapper/**/*.xml
global-config:
db-config:
id-type: auto
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
5.在Navicat中执行sql脚本
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for user_kmmy
-- ----------------------------
DROP TABLE IF EXISTS `user_kmmy`;
CREATE TABLE `user_kmmy` (
`userid` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '用户ID 绝对唯一',
`email` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '用户邮箱',
`phone` varchar(11) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '用户手机',
`usertype` int(10) NOT NULL DEFAULT 0 COMMENT '用户权限类型:0普通,1管理员',
`subuser` tinyint(2) UNSIGNED NOT NULL DEFAULT 0 COMMENT '是否有子账户',
`uname` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '用户名',
`passwd` char(40) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '密码',
`isactive` tinyint(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT '是否激活',
`salt` char(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '加密盐值',
`head_img` varchar(60) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '用户头像',
`locked` tinyint(2) NOT NULL DEFAULT 0 COMMENT '禁用账号 : 0 正常 , 1 禁用',
`create_time` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '账号创建时间',
`last_login_time` timestamp(0) NULL DEFAULT CURRENT_TIMESTAMP COMMENT '用户最后登陆时间',
`update_time` timestamp(0) NULL DEFAULT CURRENT_TIMESTAMP COMMENT '管理员更新用户状态的时间',
PRIMARY KEY (`userid`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 12 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '用户表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of user_kmmy
-- ----------------------------
INSERT INTO `user_kmmy` VALUES (10, '', '', 0, 0, '用户Root', '54725db42d08af904bb26647bc2b892f', 0, '2d793d799d5f4e3f9eafa9522f6b4fb2', '/images/defaultUserTitle.jpg', 0, '2020-06-05 13:43:52', '2020-06-05 13:43:52', '2020-06-05 13:43:52', NULL, NULL);
SET FOREIGN_KEY_CHECKS = 1;
6.修改主启动类,在主启动类上加上@MapperScan注解,后面跟自己的项目组名
@MapperScan(basePackages = {"com.kmmy.app*.mapper"})
三、
1.新建common包
包下创建工具类
MD5Utils
/**
* @author zsj
* 2019-08-20
*/
public class MD5Utils {
/**
* 使用md5的算法进行加密
*/
public static String md5(String plainText) {
byte[] secretBytes = null;
try {
secretBytes = MessageDigest.getInstance("md5").digest(
plainText.getBytes());
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("没有md5这个算法!");
}
// 16进制数字
String md5code = new BigInteger(1, secretBytes).toString(16);
// 如果生成数字未满32位,需要前面补0
for (int i = 0; i < 32 - md5code.length(); i++) {
md5code = "0" + md5code;
}
return md5code;
}
// fdgdfgvsdfgs5e5a3c75d4e1
public static void main(String[] args) {
System.out.println(md5("E10ADC3949BA59ABBE56E057F20F883E"));
}
OutputObject
/**
* @Description: 出参对象
* @Author: zsj
* @CreateDate: 2019/8/16 19:43
* @UpdateRemark: 修改内容
* @Version: 1.0
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class OutputObject implements Serializable {
/**
* 响应码
*/
private String respCode;
/**
* 响应信息
*/
private String respMessage;
/**
* 响应数据
*/
private Object data;
/**
* toString
*
* @return
*/
@Override
public String toString() {
return "OutputObject{" +
"respCode='" + respCode + '\'' +
", respMessage='" + respMessage + '\'' +
", data=" + data +
'}';
}
ResultObj
/**
* @Author: zsj
* @Date: 2019/11/21 21:35
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ResultObj {
private String respCode;
private String respMessage;
public static final ResultObj LOGIN_SUCCESS = new ResultObj(ReturnCode.SUCCESS, "登陆成功");
public static final ResultObj LOGIN_FAIL_PASS = new ResultObj(ReturnCode.FAIL, "用户名或密码错误");
public static final ResultObj LOGIN_FAIL_CODE = new ResultObj(ReturnCode.FAIL, "验证码错误");
public static final ResultObj THE_USER_ALREADY_EXISTS = new ResultObj(ReturnCode.FAIL, "该用户已存在");
public static final ResultObj ADD_SUCCESS = new ResultObj(ReturnCode.SUCCESS, "添加成功");
public static final ResultObj ADD_ERROR= new ResultObj(ReturnCode.FAIL, "添加失败");
public static final ResultObj DELETE_SUCCESS = new ResultObj(ReturnCode.SUCCESS, "删除成功");
public static final ResultObj DELETE_FAIL = new ResultObj(ReturnCode.FAIL, "删除失败");
public static final ResultObj UPDATE_SUCCESS = new ResultObj(ReturnCode.SUCCESS, "修改成功");
public static final ResultObj UPDATE_FAIL = new ResultObj(ReturnCode.FAIL, "修改失败");
public static final ResultObj ILLEGAL_MOBILE_NUMBER = new ResultObj(ReturnCode.FAIL, "手机号不合法");
public static final ResultObj RESET_SUCCESS = new ResultObj(ReturnCode.SUCCESS, "重置成功");
public static final ResultObj RESET_FAIL = new ResultObj(ReturnCode.FAIL, "重置失败");
public static final ResultObj DISPATCH_SUCCESS = new ResultObj(ReturnCode.SUCCESS, "分配成功");
public static final ResultObj DISPATCH_FAIL = new ResultObj(ReturnCode.FAIL, "分配失败");
public static final ResultObj BACKINPORT_SUCCESS = new ResultObj(ReturnCode.SUCCESS, "退货成功");
public static final ResultObj BACKINPORT_FAIL = new ResultObj(ReturnCode.FAIL, "退货失败");
public static final ResultObj SYNCCACHE_SUCCESS = new ResultObj(ReturnCode.SUCCESS, "同步缓存成功");
public static final ResultObj DELETE_FAIL_NEWS = new ResultObj(ReturnCode.FAIL, "删除用户失败,该用户是其他用户的直属领导,请先修改该用户的下属的直属领导,再进行删除操作");
public static final ResultObj DELETE_QUERY = new ResultObj();
}
ReturnCode
/**
* 响应码
*
* @author zhushaojie
*/
public class ReturnCode {
/**
* 成功
*/
public static final String SUCCESS = "200";
/**
* 失败
*/
public static final String FAIL = "400";
/**
* 未签证
*/
public static final String UNAUTHORIZED = "401";
/**
* 未找到接口
*/
public static final String NOT_FOUND = "404";
/**
* 服务器内部错误
*/
public static final String INTERNAL_SERVER_ERROR = "500";
/**
* 用户默认图片
*/
public static final String DEFAULT_IMG_USER = "/images/defaultUserTitle.jpg";
}
TokenUtil
public class TokenUtil {
private static final long EXPIRE_TIME= 10*60*60*1000;
private static final String TOKEN_SECRET="txdy"; //密钥盐
/**
* 签名生成
* @param user
* @return
*/
public static String sign(UserKmmy user){
String token = null;
try {
Date expiresAt = new Date(System.currentTimeMillis() + EXPIRE_TIME);
token = JWT.create()
.withIssuer("auth0")
.withClaim("username", user.getUname())
.withExpiresAt(expiresAt)
// 使用了HMAC256加密算法。
.sign(Algorithm.HMAC256(TOKEN_SECRET));
} catch (Exception e){
e.printStackTrace();
}
return token;
}
/**
* 签名验证
* @param token
* @return
*/
public static boolean verify(String token){
try {
JWTVerifier verifier = JWT.require(Algorithm.HMAC256(TOKEN_SECRET)).withIssuer("auth0").build();
DecodedJWT jwt = verifier.verify(token);
System.out.println("认证通过:");
System.out.println("username: " + jwt.getClaim("username").asString());
System.out.println("过期时间: " + jwt.getExpiresAt());
return true;
} catch (Exception e){
return false;
}
}
}
UUIDUtils
/**
* @author zsj
* @version 1.0
* @className com.deyi.govaffair.util.UUIDUtils
* @date: 2019/8/20 10:36
* @description TODO
*/
public class UUIDUtils {
public static String getUUID() {
return UUID.randomUUID().toString().replace("-","");
}
public static void main(String[] args) {
System.out.println(getUUID());
}
}
四、新建config包
创建MybatisPlusConfig类
/**
* @Author: zhushaojie
* @Date: 2019/11/23 19:16
*/
@Configuration
@ConditionalOnClass(value = {PaginationInterceptor.class})
public class MybatisPlusConfig {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Bean
public PaginationInterceptor paginationInterceptor() {
logger.info("====Mybatis Plus====");
return new PaginationInterceptor();
}
}
WebConfiguration
/**
* 跨域请求支持/token拦截
* tip:只能写在一个配置类里
*/
@Configuration
public class WebConfiguration implements WebMvcConfigurer {
private TokenInterceptor tokenInterceptor;
private final Logger logger = LoggerFactory.getLogger(this.getClass());
//构造方法
public WebConfiguration(TokenInterceptor tokenInterceptor){
this.tokenInterceptor = tokenInterceptor;
}
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowCredentials(true)
.allowedHeaders("*")
.maxAge(3600)
.allowedMethods("GET","POST","DELETE","PUT")
.allowedOrigins("*");
logger.info("====解决跨域问题成功!!!====");
}
@Override
public void configureAsyncSupport(AsyncSupportConfigurer configurer){
configurer.setTaskExecutor(new ConcurrentTaskExecutor(Executors.newFixedThreadPool(3)));
configurer.setDefaultTimeout(30000);
}
@Override
public void addInterceptors(InterceptorRegistry registry){
List<String> excludePath = new ArrayList<>();
// 排除拦截
excludePath.add("/user/**"); //登录
excludePath.add("/webjars/**");
excludePath.add("/static/**"); //静态资源
excludePath.add("/assets/**"); //静态资源
logger.info("====通过登录拦截器====");
registry.addInterceptor(tokenInterceptor)
.addPathPatterns("/**")
.excludePathPatterns(excludePath);
WebMvcConfigurer.super.addInterceptors(registry);
}
}
五、新建interceptor包
创建WebConfiguration类
@Component
public class TokenInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception{
if(request.getMethod().equals("OPTIONS")){
response.setStatus(HttpServletResponse.SC_OK);
return true;
}
response.setCharacterEncoding("utf-8");
String token = request.getHeader("token");
if(token != null){
boolean result = TokenUtil.verify(token);
if(result){
System.out.println("通过拦截器");
return true;
}
}
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json; charset=utf-8");
try{
JSONObject json = new JSONObject();
json.put("msg","token verify fail");
json.put("code","50000");
response.getWriter().append(json.toJSONString());
System.out.println("认证失败,未通过拦截器");
}catch (Exception e){
e.printStackTrace();
response.sendError(500);
return false;
}
return false;
}
}
六、新建pojo包
创建UserKmmy实体类
/**
* <p>
* 用户表
* </p>
*
* @author 朱少杰
* @since 2020-06-04
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class UserKmmy implements Serializable {
private static final long serialVersionUID=1L;
/**
* 用户ID 绝对唯一
*/
@TableId(value = "userid", type = IdType.AUTO)
private Long userid;
/**
* 用户邮箱
*/
private String email;
/**
* 用户手机
*/
private String phone;
/**
* 用户权限类型:0普通,1管理员
*/
private Integer usertype;
/**
* 是否有子账户
*/
private Integer subuser;
/**
* 用户名
*/
private String uname;
/**
* 密码
*/
private String passwd;
/**
* 是否激活
*/
private Boolean isactive;
/**
* 加密盐值
*/
private String salt;
/**
* 用户头像
*/
private String headImg;
/**
* 禁用账号 : 0 正常 , 1 禁用
*/
private Integer locked;
/**
* 账号创建时间
*/
private Date createTime;
/**
* 用户最后登陆时间
*/
private Date lastLoginTime;
/**
* 管理员更新用户状态的时间
*/
private Date updateTime;
public UserKmmy(String uname, String passwd) {
this.uname = uname;
this.passwd = passwd;
}
}
七、创建controller包
创建UserController类
/**
* <p>
* 用户表 前端控制器
* </p>
*
* @author 朱少杰
* @since 2020-06-04
*/
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@PostMapping("login")
@ResponseBody
public OutputObject login(@RequestBody UserKmmy user){
QueryWrapper<UserKmmy> queryWrapper = new QueryWrapper<>();
queryWrapper.eq(user.getUname() != null, "uname", user.getUname());
UserKmmy users = userService.getOne(queryWrapper);
// 密码校验
String s = (MD5Utils.md5(user.getPasswd()+users.getSalt()));
if (users.getPasswd().equals(s)==false){
return new OutputObject(ReturnCode.FAIL,"密码不正确",user);
}
queryWrapper.in(user.getPasswd() != null, "passwd", s);
// 通过用户名从数据库中查询出该用户
if (users == null){
return new OutputObject(ReturnCode.FAIL,"用户不存在",user);
}
String token = TokenUtil.sign(new UserKmmy(user.getUname(),s));
HashMap<String,Object> hs =new HashMap<>();
hs.put("token",token);
hs.put("userid",users.getUserid());
return new OutputObject(String.valueOf(HttpStatus.OK.value()),"成功",hs);
}
/**
* 用户注册
* @param user
* @return
*/
@PostMapping("addUser")
@ResponseBody
public ResultObj addUser(@RequestBody UserKmmy user) {
try {
// 查询用户名是否存在
QueryWrapper<UserKmmy> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("uname",user.getUname());
UserKmmy users = userService.getOne(queryWrapper);
if (users!=null){
return ResultObj.THE_USER_ALREADY_EXISTS;
}
// 设置盐
String salt = UUIDUtils.getUUID();
user.setSalt(salt);
// 设置密码加密
String s = MD5Utils.md5(user.getPasswd()+salt);
// 设置用户默认头像
user.setPasswd(s);
user.setHeadImg(ReturnCode.DEFAULT_IMG_USER);
userService.save(user);
return ResultObj.ADD_SUCCESS;
} catch (Exception e) {
e.printStackTrace();
return ResultObj.ADD_ERROR;
}
}
@RequestMapping("/index")
public String index() {
return "Hello World! 欢迎来到 spring boot application";
}
}
八、创建service包
1.新建UserService接口类
/**
* <p>
* 用户表 服务类
* </p>
*
* @author 朱少杰
* @since 2020-06-04
*/
public interface UserService extends IService<UserKmmy> {
}
2.在service层下创建impl包
并创建UserServiceImpl类
/**
* <p>
* 用户表 服务实现类
* </p>
*
* @author 朱少杰
* @since 2020-06-04
*/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, UserKmmy> implements UserService {
}
九、创建mapper包
包下新建UserMapper类
public interface UserMapper extends BaseMapper<UserKmmy> {
}
十、在resources下新建mapper,在这个下面新建是为了方便idea编译
在mapper下新建UserMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.kmmy.app.mapper.UserMapper">
</mapper>
到这里登录项目就完成了,启动项目
启动成功截图
测试登录,我在这里使用的postman接口测试工具进行测试
{
"uname":"用户Root",
"passwd":"1111"
}
到这里整个项目就结束了,有遇到问题的小伙伴可以下方评论或者关注微信公众号联系我,希望能帮助到你们!
本文地址:https://blog.csdn.net/qq_41645986/article/details/110819400
上一篇: C语言实现扫雷游戏简易版
下一篇: Java面试题_第三阶段