①.大事件的目录:
![](https://i-blog.csdnimg.cn/blog_migrate/548b30eea995bb17fbfe3fd7bf5a4c63.png)
①用户端的实现:用户登录、注册
com.itheima.pojo.User
package com.itheima.pojo;
import com.fasterxml.jackson.annotation.JsonIgnore;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import lombok.Data;
import java.time.LocalDateTime;
//lombok 在编译阶段,为实体类自动生成setter getter toString
// pom文件中引入依赖 在实体类上添加注解
@Data
public class User {
@NotNull
private Integer id;//主键ID
private String username;//用户名
@JsonIgnore//让springmvc把当前对象转换成json字符串的时候,忽略password,最终的json字符串中就没有password这个属性了
private String password;//密码
@NotEmpty
@Pattern(regexp = "^\\S{1,10}$")
private String nickname;//昵称
@NotEmpty
@Email
private String email;//邮箱
private String userPic;//用户头像地址
private LocalDateTime createTime;//创建时间
private LocalDateTime updateTime;//更新时间
}
com.itheima.controller.UserController
package com.itheima.controller;
import com.itheima.pojo.Result;
import com.itheima.pojo.User;
import com.itheima.service.UserService;
import com.itheima.utils.JwtUtil;
import com.itheima.utils.Md5Util;
import com.itheima.utils.ThreadLocalUtil;
import jakarta.validation.constraints.Pattern;
import org.hibernate.validator.constraints.URL;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@RestController
@RequestMapping("/user")
@Validated
public class UserController {
@Autowired
private UserService userService;
@Autowired
private StringRedisTemplate stringRedisTemplate;
//用户实现注册
@PostMapping("/register")
public Result register(@Pattern(regexp = "^\\S{5,16}$") String username, @Pattern(regexp = "^\\S{5,16}$") String password) {
//查询用户
User u = userService.findByUserName(username);
if (u == null) {
//没有占用
//注册
userService.register(username, password);
return Result.success();
} else {
//占用
return Result.error("用户名已被占用");
}
}
// 用户实现登录
@PostMapping("/login")
public Result<String> login(@Pattern(regexp = "^\\S{5,16}$") String username, @Pattern(regexp = "^\\S{5,16}$") String password) {
//根据用户名查询用户
User loginUser = userService.findByUserName(username);
//判断该用户是否存在
if (loginUser == null) {
return Result.error("用户名错误");
}
//判断密码是否正确 loginUser对象中的password是密文
if (Md5Util.getMD5String(password).equals(loginUser.getPassword())) {
//登录成功
Map<String, Object> claims = new HashMap<>();
claims.put("id", loginUser.getId());
claims.put("username", loginUser.getUsername());
String token = JwtUtil.genToken(claims);
//把token存储到redis中
ValueOperations<String, String> operations = stringRedisTemplate.opsForValue();
operations.set(token,token,1, TimeUnit.HOURS);
return Result.success(token);
}
return Result.error("密码错误");
}
//实现了查询某个用户
@GetMapping("/userInfo")
public Result<User> userInfo(/*@RequestHeader(name = "Authorization") String token*/) {
//根据用户名查询用户
/* Map<String, Object> map = JwtUtil.parseToken(token);
String username = (String) map.get("username");*/
Map<String, Object> map = ThreadLocalUtil.get();
String username = (String) map.get("username");
User user = userService.findByUserName(username);
return Result.success(user);
}
//用户实现了更新
@PutMapping("/update")
public Result update(@RequestBody @Validated User user) {
userService.update(user);
return Result.success();
}
//用户更新了部分的代码→更新了头像
@PatchMapping("updateAvatar")
public Result updateAvatar(@RequestParam @URL String avatarUrl) {
userService.updateAvatar(avatarUrl);
return Result.success();
}
//实现了部分的更新→更新了密码
@PatchMapping("/updatePwd")
public Result updatePwd(@RequestBody Map<String, String> params,@RequestHeader("Authorization") String token) {
//1.校验参数
String oldPwd = params.get("old_pwd");
String newPwd = params.get("new_pwd");
String rePwd = params.get("re_pwd");
if (!StringUtils.hasLength(oldPwd) || !StringUtils.hasLength(newPwd) || !StringUtils.hasLength(rePwd)) {
return Result.error("缺少必要的参数");
}
//原密码是否正确
//调用userService根据用户名拿到原密码,再和old_pwd比对
Map<String,Object> map = ThreadLocalUtil.get();
String username = (String) map.get("username");
User loginUser = userService.findByUserName(username);
if (!loginUser.getPassword().equals(Md5Util.getMD5String(oldPwd))){
return Result.error("原密码填写不正确");
}
//newPwd和rePwd是否一样
if (!rePwd.equals(newPwd)){
return Result.error("两次填写的新密码不一样");
}
//2.调用service完成密码更新
userService.updatePwd(newPwd);
//删除redis中对应的token
ValueOperations<String, String> operations = stringRedisTemplate.opsForValue();
operations.getOperations().delete(token);
return Result.success();
}
}
com.itheima.service.UserService
package com.itheima.service;
import com.itheima.pojo.User;
public interface UserService {
//根据用户名查询用户
User findByUserName(String username);
//注册
void register(String username, String password);
//更新
void update(User user);
//更新头像
void updateAvatar(String avatarUrl);
//更新密码
void updatePwd(String newPwd);
}
com.itheima.service.impl.UserServiceImpl
package com.itheima.service.impl;
import com.itheima.mapper.UserMapper;
import com.itheima.pojo.User;
import com.itheima.service.UserService;
import com.itheima.utils.Md5Util;
import com.itheima.utils.ThreadLocalUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.Map;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public User findByUserName(String username) {
User u = userMapper.findByUserName(username);
return u;
}
@Override
public void register(String username, String password) {
//加密
String md5String = Md5Util.getMD5String(password);
//添加
userMapper.add(username,md5String);
}
@Override
public void update(User user) {
user.setUpdateTime(LocalDateTime.now());
userMapper.update(user);
}
@Override
public void updateAvatar(String avatarUrl) {
Map<String,Object> map = ThreadLocalUtil.get();
Integer id = (Integer) map.get("id");
userMapper.updateAvatar(avatarUrl,id);
}
@Override
public void updatePwd(String newPwd) {
Map<String,Object> map = ThreadLocalUtil.get();
Integer id = (Integer) map.get("id");
userMapper.updatePwd(Md5Util.getMD5String(newPwd),id);
}
}
com.itheima.mapper.UserMapper.java
package com.itheima.mapper;
import com.itheima.pojo.User;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
@Mapper
public interface UserMapper {
//根据用户名查询用户
@Select("select * from user where username=#{username}")
User findByUserName(String username);
//添加
@Insert("insert into user(username,password,create_time,update_time)" +
" values(#{username},#{password},now(),now())")
void add(String username, String password);
@Update("update user set nickname=#{nickname},email=#{email},update_time=#{updateTime} where id=#{id}")
void update(User user);
@Update("update user set user_pic=#{avatarUrl},update_time=now() where id=#{id}")
void updateAvatar(String avatarUrl,Integer id);
@Update("update user set password=#{md5String},update_time=now() where id=#{id}")
void updatePwd(String md5String, Integer id);
}
②文章目录展示
pojo.Category
package com.itheima.pojo;
import com.fasterxml.jackson.annotation.JsonFormat;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.groups.Default;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class Category {
@NotNull(groups = Update.class)
private Integer id;//主键ID
@NotEmpty
private String categoryName;//分类名称
@NotEmpty
private String categoryAlias;//分类别名
private Integer createUser;//创建人ID
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime;//创建时间
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateTime;//更新时间
//如果说某个校验项没有指定分组,默认属于Default分组
//分组之间可以继承, A extends B 那么A中拥有B中所有的校验项
public interface Add extends Default {
}
public interface Update extends Default{
}
}
controller/CategoryController.java
package com.itheima.controller;
import com.itheima.pojo.Category;
import com.itheima.pojo.Result;
import com.itheima.service.CategoryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/category")
public class CategoryController {
@Autowired
private CategoryService categoryService;
//实现文章目录的添加
@PostMapping
public Result add(@RequestBody @Validated(Category.Add.class) Category category){
categoryService.add(category);
return Result.success();
}
//查询文章目录的
@GetMapping
public Result<List<Category>> list(){
List<Category> cs = categoryService.list();
return Result.success(cs);
}
// 实现修改,显示文章的目录:查询文章目录的细节
@GetMapping("/detail")
public Result<Category> detail(Integer id){
Category c = categoryService.findById(id);
return Result.success(c);
}
//更新文章的目录
@PutMapping
public Result update(@RequestBody @Validated(Category.Update.class) Category category){
categoryService.update(category);
return Result.success();
}
//删除文章的目录
@DeleteMapping
public Result delete(Integer id){
categoryService.deleteById(id);
return Result.success();
}
}
service/CategoryService.java
package com.itheima.service;
import com.itheima.pojo.Category;
import java.util.List;
public interface CategoryService {
//新增分类
void add(Category category);
//列表查询
List<Category> list();
//根据id查询分类信息
Category findById(Integer id);
//更新分类
void update(Category category);
//删除分类
void deleteById(Integer id);
}
service/impl/CategoryServiceImpl.java
package com.itheima.service.impl;
import com.itheima.mapper.CategoryMapper;
import com.itheima.pojo.Category;
import com.itheima.service.CategoryService;
import com.itheima.utils.ThreadLocalUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
@Service
public class CategoryServiceImpl implements CategoryService {
@Autowired
private CategoryMapper categoryMapper;
@Override
public void add(Category category) {
//补充属性值
category.setCreateTime(LocalDateTime.now());
category.setUpdateTime(LocalDateTime.now());
Map<String,Object> map = ThreadLocalUtil.get();
Integer userId = (Integer) map.get("id");
category.setCreateUser(userId);
categoryMapper.add(category);
}
@Override
public List<Category> list() {
Map<String,Object> map = ThreadLocalUtil.get();
Integer userId = (Integer) map.get("id");
return categoryMapper.list(userId);
}
@Override
public Category findById(Integer id) {
Category c = categoryMapper.findById(id);
return c;
}
@Override
public void update(Category category) {
category.setUpdateTime(LocalDateTime.now());
categoryMapper.update(category);
}
@Override
public void deleteById(Integer id) {
categoryMapper.deleteById(id);
}
}
mapper/CategoryMapper.java
package com.itheima.mapper;
import com.itheima.pojo.Category;
import org.apache.ibatis.annotations.*;
import org.springframework.web.bind.annotation.DeleteMapping;
import java.util.List;
@Mapper
public interface CategoryMapper {
//新增
@Insert("insert into category(category_name,category_alias,create_user,create_time,update_time) " +
"values(#{categoryName},#{categoryAlias},#{createUser},#{createTime},#{updateTime})")
void add(Category category);
//查询所有
@Select("select * from category where create_user = #{userId}")
List<Category> list(Integer userId);
//根据id查询
@Select("select * from category where id = #{id}")
Category findById(Integer id);
//更新
@Update("update category set category_name=#{categoryName},category_alias=#{categoryAlias},update_time=#{updateTime} where id=#{id}")
void update(Category category);
//根据id删除
@Delete("delete from category where id=#{id}")
void deleteById(Integer id);
}
③实现文章的添加
pojo.Article
package com.itheima.pojo;
import com.itheima.anno.State;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import lombok.Data;
import org.hibernate.validator.constraints.URL;
import java.time.LocalDateTime;
@Data
public class Article {
private Integer id;//主键ID
@NotEmpty
@Pattern(regexp = "^\\S{1,10}$")
private String title;//文章标题
@NotEmpty
private String content;//文章内容
@NotEmpty
@URL
private String coverImg;//封面图像
@State
private String state;//发布状态 已发布|草稿
@NotNull
private Integer categoryId;//文章分类id
private Integer createUser;//创建人ID
private LocalDateTime createTime;//创建时间
private LocalDateTime updateTime;//更新时间
}
对state字段的自定义校验:
package com.itheima.anno;
import com.itheima.validation.StateValidation;
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
import jakarta.validation.constraints.NotEmpty;
import java.lang.annotation.Documented;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.ElementType.TYPE_USE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Documented//元注解
@Target({ FIELD})//元注解,用在那个元素上
@Retention(RUNTIME)//元注解
@Constraint(validatedBy = { StateValidation.class})//指定提供校验规则的类
public @interface State {
//提供校验失败后的提示信息
String message() default "state参数的值只能是已发布或者草稿";
//指定分组
Class<?>[] groups() default { };
//负载 获取到State注解的附加信息
Class<? extends Payload>[] payload() default { };
}
指定提供校验规则的类:anno.State
package com.itheima.validation;
import com.itheima.anno.State;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
public class StateValidation implements ConstraintValidator<State,String> {
/**
*
* @param value 将来要校验的数据
* @param context context in which the constraint is evaluated
*
* @return 如果返回false,则校验不通过,如果返回true,则校验通过
*/
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
//提供校验规则
if (value == null){
return false;
}
if (value.equals("已发布") || value.equals("草稿")){
return true;
}
return false;
}
}
pojo.PageBean
package com.itheima.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
//分页返回结果对象
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PageBean <T>{
private Long total;//总条数
private List<T> items;//当前页数据集合
}
service.ArticleService
package com.itheima.service;
import com.itheima.pojo.Article;
import com.itheima.pojo.Category;
import com.itheima.pojo.PageBean;
public interface ArticleService {
//新增文章
void add(Article article);
//条件分页列表查询
PageBean<Article> list(Integer pageNum, Integer pageSize, Integer categoryId, String state);
}
service.ArticleServiceImpl
package com.itheima.service.impl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.itheima.mapper.ArticleMapper;
import com.itheima.pojo.Article;
import com.itheima.pojo.PageBean;
import com.itheima.service.ArticleService;
import com.itheima.utils.ThreadLocalUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
@Service
public class ArticleServiceImpl implements ArticleService {
@Autowired
private ArticleMapper articleMapper;
@Override
public void add(Article article) {
//补充属性值
article.setCreateTime(LocalDateTime.now());
article.setUpdateTime(LocalDateTime.now());
Map<String,Object> map = ThreadLocalUtil.get();
Integer userId = (Integer) map.get("id");
article.setCreateUser(userId);
articleMapper.add(article);
}
@Override
public PageBean<Article> list(Integer pageNum, Integer pageSize, Integer categoryId, String state) {
//1.创建PageBean对象
PageBean<Article> pb = new PageBean<>();
//2.开启分页查询 PageHelper
PageHelper.startPage(pageNum,pageSize);
//3.调用mapper
Map<String,Object> map = ThreadLocalUtil.get();
Integer userId = (Integer) map.get("id");
List<Article> as = articleMapper.list(userId,categoryId,state);
//Page中提供了方法,可以获取PageHelper分页查询后 得到的总记录条数和当前页数据
Page<Article> p = (Page<Article>) as;
//把数据填充到PageBean对象中
pb.setTotal(p.getTotal());
pb.setItems(p.getResult());
return pb;
}
}
mapper.ArticleMapper.java
package com.itheima.mapper;
import com.itheima.pojo.Article;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface ArticleMapper {
//新增
@Insert("insert into article(title,content,cover_img,state,category_id,create_user,create_time,update_time) " +
"values(#{title},#{content},#{coverImg},#{state},#{categoryId},#{createUser},#{createTime},#{updateTime})")
void add(Article article);
List<Article> list(Integer userId, Integer categoryId, String state);
}
mapper.ArticleMapper.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.itheima.mapper.ArticleMapper">
<!--动态sql-->
<select id="list" resultType="com.itheima.pojo.Article">
select * from article
<where>
<if test="categoryId!=null">
category_id=#{categoryId}
</if>
<if test="state!=null">
and state=#{state}
</if>
and create_user=#{userId}
</where>
</select>
</mapper>
④实现图片的上传:
controller.FileUploadController
package com.itheima.controller;
import com.itheima.pojo.Result;
import com.itheima.utils.AliOssUtil;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.util.UUID;
@RestController
public class FileUploadController {
@PostMapping("/upload")
public Result<String> upload(MultipartFile file) throws Exception {
//把文件的内容存储到本地磁盘上
String originalFilename = file.getOriginalFilename();
//保证文件的名字是唯一的,从而防止文件覆盖
String filename = UUID.randomUUID().toString()+originalFilename.substring(originalFilename.lastIndexOf("."));
//file.transferTo(new File("C:\\Users\\Administrator\\Desktop\\files\\"+filename));
String url = AliOssUtil.uploadFile(filename,file.getInputStream());
return Result.success(url);
}
}
工具类:utils.AliOssUtil
package com.itheima.utils;
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.PutObjectResult;
import java.io.FileInputStream;
import java.io.InputStream;
public class AliOssUtil {
// Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
private static final String ENDPOINT = "oss-cn-shenzhen.aliyuncs.com";
// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
//EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
private static final String ACCESS_KEY_ID="LTAI5tFJyX2vffsJpSukcH7j";
private static final String ACCESS_KEY_SECRET="udjA9dLPeifWibS6Epydy3ew0PMYn3";
// 填写Bucket名称,例如examplebucket。
private static final String BUCKET_NAME = "big-event110";
public static String uploadFile(String objectName, InputStream in) throws Exception {
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(ENDPOINT,ACCESS_KEY_ID, ACCESS_KEY_SECRET);
String url = "";
try {
// 填写字符串。
String content = "Hello OSS,你好世界";
// 创建PutObjectRequest对象。
PutObjectRequest putObjectRequest = new PutObjectRequest(BUCKET_NAME, objectName, in);
// 如果需要上传时设置存储类型和访问权限,请参考以下示例代码。
// ObjectMetadata metadata = new ObjectMetadata();
// metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());
// metadata.setObjectAcl(CannedAccessControlList.Private);
// putObjectRequest.setMetadata(metadata);
// 上传字符串。
PutObjectResult result = ossClient.putObject(putObjectRequest);
//url组成: https://bucket名称.区域节点/objectName
url = "https://"+BUCKET_NAME+"."+ENDPOINT.substring(ENDPOINT.lastIndexOf("/")+1)+"/"+objectName;
} catch (OSSException oe) {
System.out.println("Caught an OSSException, which means your request made it to OSS, "
+ "but was rejected with an error response for some reason.");
System.out.println("Error Message:" + oe.getErrorMessage());
System.out.println("Error Code:" + oe.getErrorCode());
System.out.println("Request ID:" + oe.getRequestId());
System.out.println("Host ID:" + oe.getHostId());
} catch (ClientException ce) {
System.out.println("Caught an ClientException, which means the client encountered "
+ "a serious internal problem while trying to communicate with OSS, "
+ "such as not being able to access the network.");
System.out.println("Error Message:" + ce.getMessage());
} finally {
if (ossClient != null) {
ossClient.shutdown();
}
}
return url;
}
}
④其他的配置:
全局异常处理:exception.GlobalExceptionHandler
package com.itheima.exception;
import com.itheima.pojo.Result;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public Result handleException(Exception e){
e.printStackTrace();
//要么有异常、或者是操作错误
return Result.error(StringUtils.hasLength(e.getMessage())? e.getMessage() : "操作失败");
}
}
登录拦截器:interceptors.LoginInterceptor
- 使用到了redis:防止更改了密码,但是token依然没有变化
package com.itheima.interceptors;
import com.itheima.pojo.Result;
import com.itheima.utils.JwtUtil;
import com.itheima.utils.ThreadLocalUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import java.util.Map;
@Component
public class LoginInterceptor implements HandlerInterceptor {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//令牌验证
String token = request.getHeader("Authorization");
//验证token
try {
//从redis中获取相同的token
ValueOperations<String, String> operations = stringRedisTemplate.opsForValue();
String redisToken = operations.get(token);
if (redisToken==null){
//token已经失效了
throw new RuntimeException();
}
Map<String, Object> claims = JwtUtil.parseToken(token);
//把业务数据存储到ThreadLocal中
ThreadLocalUtil.set(claims);
//放行
return true;
} catch (Exception e) {
//http响应状态码为401
response.setStatus(401);
//不放行
return false;
}
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
//清空ThreadLocal中的数据
ThreadLocalUtil.remove();
}
}
拦截生效的地方配置:config.WebConfig
package com.itheima.config;
import com.itheima.interceptors.LoginInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private LoginInterceptor loginInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
//登录接口和注册接口不拦截
registry.addInterceptor(loginInterceptor).excludePathPatterns("/user/login","/user/register");
}
}
对返回结果的封装:Result
package com.itheima.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
//统一响应结果
@NoArgsConstructor
@AllArgsConstructor
@Data
public class Result<T> {
private Integer code;//业务状态码 0-成功 1-失败
private String message;//提示信息
private T data;//响应数据
//快速返回操作成功响应结果(带响应数据)
public static <E> Result<E> success(E data) {
return new Result<>(0, "操作成功", data);
}
//快速返回操作成功响应结果
public static Result success() {
return new Result(0, "操作成功", null);
}
public static Result error(String message) {
return new Result(1, message, null);
}
}
生成jwt:把id、name
package com.itheima.utils;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import java.util.Date;
import java.util.Map;
public class JwtUtil {
private static final String KEY = "itheima";
//接收业务数据,生成token并返回
public static String genToken(Map<String, Object> claims) {
return JWT.create()
.withClaim("claims", claims)
.withExpiresAt(new Date(System.currentTimeMillis() + 1000 * 60 * 60 ))
.sign(Algorithm.HMAC256(KEY));
}
//取得claims信息:接收token,验证token,并返回业务数据
public static Map<String, Object> parseToken(String token) {
return JWT.require(Algorithm.HMAC256(KEY))
.build()
.verify(token)
.getClaim("claims")
.asMap();
}
}
utils.ThreadLocalUtil:把claim(id,name存储到线程中去)
package com.itheima.utils;
import java.util.HashMap;
import java.util.Map;
/**
* ThreadLocal 工具类
*/
@SuppressWarnings("all")
public class ThreadLocalUtil {
//提供ThreadLocal对象,
private static final ThreadLocal THREAD_LOCAL = new ThreadLocal();
//根据键获取值
public static <T> T get(){
return (T) THREAD_LOCAL.get();
}
//存储键值对
public static void set(Object value){
THREAD_LOCAL.set(value);
}
//清除ThreadLocal 防止内存泄漏
public static void remove(){
THREAD_LOCAL.remove();
}
}
utils.Md5Util:对密码进行加密
package com.itheima.utils;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class Md5Util {
/**
* 默认的密码字符串组合,用来将字节转换成 16 进制表示的字符,apache校验下载的文件的正确性用的就是默认的这个组合
*/
protected static char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
protected static MessageDigest messagedigest = null;
static {
try {
messagedigest = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException nsaex) {
System.err.println(Md5Util.class.getName() + "初始化失败,MessageDigest不支持MD5Util。");
nsaex.printStackTrace();
}
}
/**
* 生成字符串的md5校验值
*
* @param s
* @return
*/
public static String getMD5String(String s) {
return getMD5String(s.getBytes());
}
/**
* 判断字符串的md5校验码是否与一个已知的md5码相匹配
*
* @param password 要校验的字符串
* @param md5PwdStr 已知的md5校验码
* @return
*/
public static boolean checkPassword(String password, String md5PwdStr) {
String s = getMD5String(password);
return s.equals(md5PwdStr);
}
public static String getMD5String(byte[] bytes) {
messagedigest.update(bytes);
return bufferToHex(messagedigest.digest());
}
private static String bufferToHex(byte bytes[]) {
return bufferToHex(bytes, 0, bytes.length);
}
private static String bufferToHex(byte bytes[], int m, int n) {
StringBuffer stringbuffer = new StringBuffer(2 * n);
int k = m + n;
for (int l = m; l < k; l++) {
appendHexPair(bytes[l], stringbuffer);
}
return stringbuffer.toString();
}
private static void appendHexPair(byte bt, StringBuffer stringbuffer) {
char c0 = hexDigits[(bt & 0xf0) >> 4];// 取字节中高 4 位的数字转换, >>>
// 为逻辑右移,将符号位一起右移,此处未发现两种符号有何不同
char c1 = hexDigits[bt & 0xf];// 取字节中低 4 位的数字转换
stringbuffer.append(c0);
stringbuffer.append(c1);
}
}