个人博客项目

文章讨论了如何在Java后端设计中处理数据库表结构,包括文章和用户表的字段。还介绍了如何使用AjaxResult进行统一数据返回,以及实现拦截器以控制未登录访问的权限。主要内容涉及数据处理、错误返回和用户认证逻辑。
摘要由CSDN通过智能技术生成

数据库的设计

有两张表,分别是文章表和用户表,文章表中包含了id,title,content,createtime,uid,rcount,stat,其中id是自增的。用户表中包含了id,title,username,password,phtot,createtime,updatetime,state,其中id是也是自增的。

  • 统一数据返回

将返回的数据进行统一函数的处理,使得返回前端的数据格式是一致的。

  • public class AjaxResult {
        /**
         * 业务执行成功进行返回的方法
         * @param data
         * @return
         */
        public static HashMap<String, Object> success(Object data){
            HashMap<String, Object> result = new HashMap<>();
            result.put("code",200);
            result.put("msg","");
            result.put("data", data);
    
            return result;
        }
        public static HashMap<String, Object> success(Object data, String msg){
            HashMap<String, Object> result = new HashMap<>();
            result.put("code",200);
            result.put("msg",msg);
            result.put("data", data);
    
            return result;
        }
    
        /**
         * 失败时返回数据格式
         * @param code
         * @param msg
         * @return
         */
        public static HashMap<String, Object> fail(int code, String msg){
            HashMap<String, Object> result = new HashMap<>();
            result.put("code",code);
            result.put("msg",msg);
            result.put("data", "");
    
            return result;
        }
        public static HashMap<String, Object> fail(int code, String msg,Object data){
            HashMap<String, Object> result = new HashMap<>();
            result.put("code",code);
            result.put("msg",msg);
            result.put("data",data);
    
            return result;
        }
    }

            统一数据返回时,和前端约定好了按照固定的格式返回。调用此方法,不管是什么类型,都是统一的数据格式返回。

    @SneakyThrows
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        if(body instanceof HashMap){
            //本身已经封装好了
            return body;
        }

        if(body instanceof String){
            //返回是一个String
            ObjectMapper objectMapper = new ObjectMapper();
            return objectMapper.writeValueAsString(AjaxResult.success(body));
        }
        
        return AjaxResult.success(body);
    }
  • 拦截器

对于未登录访问个人栏等不安全的行为,我们应该实现拦截器来阻止,拦截器的实现和拦截器配置规则如下:

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //通过session判断是否有用户的信息,方法是从session中取对象,如果存在对象,就说明已经登陆了
        HttpSession session = request.getSession(false);//false作用是,在没找到session对象时,也不能创建一个session
        if(session != null && session.getAttribute(Constant.SESSION_USERINFO_KEY) != null){
            return true;
        }else {
            response.setStatus(401);//未登录,权限不够
            return false;//登录失败
        }
    }
    //注入拦截器
    @Autowired
    private LoginInterceptor loginInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginInterceptor)
                .addPathPatterns("/**") // 拦截所有请求(url地址)
                .excludePathPatterns("/user/reg") // 排除注册接口(注册接口不拦截)
                .excludePathPatterns("/user/login")
                .excludePathPatterns("/user/getuser")
                .excludePathPatterns("/user/getsess")
                .excludePathPatterns("/user/isartbyme")
                .excludePathPatterns("/getcaptcha")
                .excludePathPatterns("/art/list")//分页页面
                .excludePathPatterns("/art/detail")
                .excludePathPatterns("/art/totalpage")
                .excludePathPatterns("/art/update_rcount")
                .excludePathPatterns("/comment/list")
                .excludePathPatterns("/**/*.html")//任意路径下的html后缀可以放行
                .excludePathPatterns("/css/**")
                .excludePathPatterns("/editor.md/**")
                .excludePathPatterns("/img/**")//img目录下所有的文件都放行
                .excludePathPatterns("/image/**")
                .excludePathPatterns("/js/**");
    }
  • 博客的基本操作

/**
 * 用户控制器
 */
@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;

    @RequestMapping("/reg")
    public Object reg(String username, String password){
        //1.非空校验,虽然前端校验了,但是后端请求不一定来自前端
        if(!StringUtils.hasLength(username) || !StringUtils.hasLength(password)){
            return AjaxResult.fail(-1, "非法参数请求");
        }
        //2.添加操作
        int result = userService.add(username,
                SecurityUtil.encrypt(password));//密码加盐
        if(result == 1){
            return AjaxResult.success(1,"添加成功");
        }else {
            return AjaxResult.fail(-1,"添加失败");
        }
    }

    //我们约定1为成功,非1为登录失败
    @RequestMapping("/login")
    @Transactional
    public int login(HttpServletRequest request, String username, String password){
        //1.非空校验,虽然前端校验了,但是后端请求不一定来自前端
        if(!StringUtils.hasLength(username) || !StringUtils.hasLength(password)){
            return 0;
        }
        //2.查询操作
        UserInfo userInfo = userService.getUserByName(username);
        if(userInfo == null || userInfo.getId() <= 0){
            return -1;
        }else {
            boolean result = SecurityUtil.decrypt(password,userInfo.getPassword()) ;
           if(result) {
               HttpSession session = request.getSession();//通过默认参数。得到session对象,使用sessionID来实现的,然后采用后面的操作
               session.setAttribute(Constant.SESSION_USERINFO_KEY, userInfo);//将常量key值和userinfo对象添加
               //虽然每个用户的session key想通,但是里面的sessionID是不一样的,这样可以来区分不同的用户
               return 1;
           }

        }
        return -1;
    }

    @RequestMapping("/myinfo")
    public UserInfo myInfo(HttpServletRequest request){
        HttpSession session = request.getSession(false);
        //判断session有值,并且有登录的值
        if(session != null &&
                session.getAttribute(Constant.SESSION_USERINFO_KEY) != null){
            return (UserInfo) session.getAttribute(Constant.SESSION_USERINFO_KEY);
        }
        return null;
    }

    /**
     * 退出登录
     * @param request
     * @return
     */
    @RequestMapping("/logout")
    public boolean logout(HttpServletRequest request){
        HttpSession session = request.getSession(false);
        //判断session有值,并且有登录的值
        if(session != null &&
                    session.getAttribute(Constant.SESSION_USERINFO_KEY) != null){
            session.removeAttribute(Constant.SESSION_USERINFO_KEY);//移除当前登录
        }

        return true;
    }

  • 密码加盐加密

随机得到32位的盐值,用md5DigestAsHex函数加密盐值加原始密码,返回盐值加加密后的密码作为最终的加密密码。

  •      /**
         * 加密
         * @param password
         * @return
         */
            public static String encrypt(String password) {
                // 随机盐值,每次的盐值都为固定的32位
                String salt = UUID.randomUUID().toString().replace("-","");
                // 最终密码(md5(随机盐值+密码))
                String finalPassword = DigestUtils.md5DigestAsHex((salt + password).getBytes());
                return salt+finalPassword;
            }

    加盐密码的校验

    public static boolean decrypt(String password, String finalPassword) {
                //非空校验
                if (!StringUtils.hasLength(password) || !StringUtils.hasLength(finalPassword)) {
                    return false;
                }
                if (finalPassword.length() != 64) {
                    return false;
                }
                //得到盐值
                String salt = finalPassword.substring(0,32);
                //使用盐值,将待确认的密码生成最终密码
                String securityPassword = DigestUtils.md5DigestAsHex((salt + password).getBytes());
                //使用盐值与最终密码进行对比
                return finalPassword.equals(salt+securityPassword);
            }

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值