博客系统(升级(Spring))(二)获取当前用户信息、对密码进行加密、设置统一数据格式、设置未登录拦截、线程池

博客系统(二)

  • 博客系统
  • 获取当前用户的信息
  • 对密码进行加密和解密的操作
  • 设置统一的数据返回格式
  • 设置未登录拦截
  • 设置线程池

博客系统

博客系统是干什么的?
CSDN就是一个典型的博客系统。而我在这里就是通过模拟实现一个博客系统,这是一个较为简单的博客系统,但是主要功能一个不缺,不过就是 UI 有些 low,我学习前端是为了写后端更加顺手。不至于前后端完全分离,但是有个问题设计的 web 页面不是很好看。

首先我将整体的业务流程展现
在这里插入图片描述
我们继博客系统(一)继续,编写

获取当前用户的信息

根据项目结构图可以知道,我们无论是登录还是查询必须要获取当前的用户的信息。

根据session的特点,他会自己生成一个cooker值,我们这里只需要获取信息,但是session是一个 key:value 结构的值,所以还需要的一个公共的,全局变量 ,key值。用来保存和查找对应的value值

/**
 * 全局变量
 */
public class Variable {
    public  static final String SESSION_USERINFO_KEY="SESSION_USERINFO";
}

博客系统(升级(Spring))(二)获取当前用户信息、对密码进行加密、设置统一数据格式、设置未登录拦截、线程池_第1张图片

接下来我们就可以根据key去寻找当前的用户信息了。

/**
 * 得到当前的用户信息
 */

public class SessionUtis {

    public static Userinfo getUser(HttpServletRequest request){
        HttpSession httpSession=request.getSession(false);
        if (httpSession!=null&&httpSession.getAttribute(Variable.SESSION_USERINFO_KEY)!=httpSession){
            return (Userinfo) httpSession.getAttribute(Variable.SESSION_USERINFO_KEY);
        }
        return null;
    }
}

博客系统(升级(Spring))(二)获取当前用户信息、对密码进行加密、设置统一数据格式、设置未登录拦截、线程池_第2张图片

对密码进行加密和解密的操作

首先 UUID 这个类是可以生产出世界上唯一的值(目前是),市面上的加密工具,有很多,我们用 MD5(C级)的就够了,毕竟是个小网站。

我规定:

  1. 最终密码生成为65位字符
  2. UUID生成的唯一值与用户所注册的密码合并通过加密工具进行加密。得到一个唯一的值
  3. 将这个唯一的值与UUID数生成的唯一的值合并。二者通过 @ 分隔
    • 因为在MD5只能正向加密不能反向解密,所以我们要将唯一的UUID进行保存,从而在解密以及验证密码正确性上有操作空间
    • java基本库里为我们提供了UUID生成类,要搭配方法 randomUUID 使用,且生成的uuid有一些特殊字符,需要我们手动去除,此时得到的是一个32位的唯一字符串
    • java基本库里为我们提供了MD5的加密工具类,DigestUtils,搭配md5DigestAsHex()使用,但是参数是一个二进制数组所以,需要getBytes转换。
/**
 * 对密码进行加密,解密
 */
public class PasswordUtils {
    /**
     * 加密
     */
    public  String encryption(String password){
        //uuid生成为唯一值
        String salt= UUID.randomUUID().toString().replace("-","");
        //将uuid和password经过MD5加密得到密码
        String finalPassword=
                DigestUtils.md5DigestAsHex((salt+password).getBytes(StandardCharsets.UTF_8));
        return salt+"@"+finalPassword;
    }
    /**
     * 解密,并验证密码正确
     */
    public static boolean decrypt(String password,String dbPassword){
        if (!StringUtils.hasLength(password)||!StringUtils.hasLength(dbPassword)||dbPassword.length()!=65){
            return false;
        }
        String [] dbPasswordArray=dbPassword.split("@");
        if (dbPasswordArray.length!=2){
            return false;
        }
        //获取唯一的uuid
        String salt=dbPasswordArray[0];
        //获取生成的md5的密码
        String finalDBpassword=dbPasswordArray[1];
        //通过同样的uuid 和 密码生成出来的值是唯一的。
        String finalPassword=DigestUtils.md5DigestAsHex((salt+password).getBytes(StandardCharsets.UTF_8));
        if (finalDBpassword.equals(finalPassword)){
            return false;
        }
        return true;
    }

博客系统(升级(Spring))(二)获取当前用户信息、对密码进行加密、设置统一数据格式、设置未登录拦截、线程池_第3张图片

设置统一的数据返回格式

设置这个的目的很简单,在开发的时候有很多人,一起开发,使得数据格式会不一样,我们在这里做一个保底策略。
这里我们需要添加一个拦截,将返回出去的数据进行统一的格式规划,这里我用常见的j son 格式

  1. ResponseBodyAdvice 接口允许在执行 @ResponseBody 或 ResponseEntity 控制器方法之后,但在使用HttpMessageConverter 写入响应体之前自定义响应,进行功能增强。通常用于 加密,签名,统一数据格式等。

  2. instanceof 是Java中的二元运算符,左边是对象,右边是类;当对象是右边类或子类所创建对象时,返回true;否则,返回false。

    • 类的实例包含本身的实例,以及所有直接或间接子类的实例

    • instanceof左边显式声明的类型与右边操作元必须是同种类或存在继承关系,也就是说需要位于同一个继承树,否则会编译错误

注意,这里返回的 object 类,但是对于ResponseBodyAdvice 来说,是没有String类型的说法所以需要自己去判断,不然就会报错

@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {
    //格式生成唯一json格式
    @Resource
    private ObjectMapper objectMapper;

    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType,
                                  MediaType selectedContentType,
                                  Class selectedConverterType,
                                  ServerHttpRequest request, ServerHttpResponse response) {
        //格式符合要求,就不用转换格式直接返回
        if (body instanceof ResultAjax){
            return body;
        }
        //格式为String类型,属于特殊类,需要我们手动调换
        if (body instanceof String){
            ResultAjax resultAjax=ResultAjax.success(body);
            try {
                //将格式转换层json格式,然后返回
                return objectMapper.writeValueAsString(resultAjax);
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
        }
        
        return ResultAjax.success(body);
    }
}

这里有不明白的可以去看我的博客-----Spring AOP (拦截器)

博客系统(升级(Spring))(二)获取当前用户信息、对密码进行加密、设置统一数据格式、设置未登录拦截、线程池_第4张图片

设置未登录拦截

上述一样不知道原理的可以去看我的 博客 Spring AOP (拦截器)

HandlerInterceptor 和 WebMvcConfigurer搭配使用,前者设置规则,设置拦截的网页

/**
 * 设置登录拦截规则
 */
public class LoginIntercept implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HttpSession httpSession=request.getSession(false);
        if (httpSession!=null&&httpSession.getAttribute(Variable.SESSION_USERINFO_KEY)!=null){
            return true;
        }
        response.sendRedirect("/login.html");
        return false;
    }
}
/**
 * 拦截的网页和资源
 */
@Configuration
public class MyConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginIntercept())
                .addPathPatterns("/**")
                .excludePathPatterns("/css/*");
    }
}

博客系统(升级(Spring))(二)获取当前用户信息、对密码进行加密、设置统一数据格式、设置未登录拦截、线程池_第5张图片

设置线程池

这里用的线程池是Spring下的,不用像java本库中的线程池,填入参数,只需要调用set方法写入(不知道线程池可以看我的多线程文章)

@Configuration
public class ThreadPoolUltisConfig {
    public ThreadPoolTaskExecutor taskExecutor(){
        ThreadPoolTaskExecutor executor=new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(10000);
        executor.setThreadNamePrefix("MyThread-");
        executor.initialize();
        return executor;
    }
}

你可能感兴趣的:(java,spring,java,后端)