电商生鲜网站开发(二)——后台开发:用户模块

62 篇文章 3 订阅

电商生鲜网站开发(二)——后台开发:用户模块

接口设计

https://blog.csdn.net/a2272062968/article/details/123385857

开发任务与知识点

登录

注册

重名校验

    @Override
    public void register(String userName, String password) throws MallException, NoSuchAlgorithmException {
        //查询用户名是否已存在
        User result = userMapper.selectByName(userName);
        if (result != null) {
            throw new MallException(MallExceptionEnum.NAME_EXISTED);
        }
        //写入数据库
        User user = new User();
        user.setUsername(userName);
//        user.setPassword(password);
        user.setPassword(MD5Utils.getMD5Str(password));

        int count = userMapper.insertSelective(user);
        if (count == 0) {
            throw new MallException(MallExceptionEnum.INSERT_FAILED);
        }
    }

密码加密存储

MD5加密类

package com.learn2333.freshmall.util;

import com.learn2333.freshmall.common.Constant;
import org.apache.tomcat.util.codec.binary.Base64;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * MD5工具
 */
public class MD5Utils {
    public static String getMD5Str(String strValue) throws NoSuchAlgorithmException {
        MessageDigest md5 = MessageDigest.getInstance("MD5");
        return Base64.encodeBase64String(md5.digest((strValue+ Constant.SALT).getBytes()));
    }
}

Session的使用(保存登录信息)用户控制层,登录时增加用户对象(抹除密码信息),退出时清空用户对象

越权交验(没有登录不能修改、只能修改自己用户的)

统一响应对象

package com.learn2333.freshmall.common;

import com.learn2333.freshmall.exception.MallExceptionEnum;

/**
 * 通用返回对象
 */
public class ApiRestResponse<T> {
    //状态码
    private Integer status;
    //信息
    private String msg;
    //范型的data
    private T data;
    //正常的状态码
    private static final int OK_CODE = 10000;
    //信息
    private static final String OK_MSG = "SUCCESS";

    public ApiRestResponse(Integer status, String msg, T data) {
        this.status = status;
        this.msg = msg;
        this.data = data;
    }

    public ApiRestResponse(Integer status, String msg) {
        this.status = status;
        this.msg = msg;
    }

    public ApiRestResponse() {
        this(OK_CODE, OK_MSG);
    }
    //成功 返回默认状态码(无参构造函数的2个常量)
    public static <T>  ApiRestResponse<T> success() {
        return new ApiRestResponse<>();
    }
    //成功 返回默认状态码和数据
    public static <T> ApiRestResponse<T> success(T result) {
        ApiRestResponse<T> response = new ApiRestResponse<>();
        response.setData(result);
        return response;
    }

    //失败 传入状态码和信息
    public static <T> ApiRestResponse<T> error(Integer code, String msg) {
        return new ApiRestResponse<>(code, msg);
    }

    //失败 传入定义的异常枚举
    public static <T> ApiRestResponse<T> error(MallExceptionEnum ex) {
        return new ApiRestResponse<>(ex.getCode(), ex.getMsg());
    }

    @Override
    public String toString() ...
get,set方法
}

异常枚举

Java异常体系

Postman实操
在这里插入图片描述

统一异常处理(使用过滤器)

更新个人信息

另外系统中的常量可定义常量类存储

package com.learn2333.freshmall.common;

/**
 * 常量值
 */
public class Constant {
    //用于加密MD5的盐值
    public static final String SALT = "https://learn2333.com/666";
    //session中用户对象的key
    public static final String MALL_USER = "mall_user";
}

案例:注册接口

@PostMapping("/register")
@ResponseBody
public ApiRestResponse register(@RequestParam("userName") String userName,@RequestParam("password") String password)

完成注册接口交验,用户名,密码

如果交验失败返回创建的通用返回对象

通用返回对象类中包含状态码,信息,范型的data,构造方法返回成功状态码,如果失败则可以传入定义的异常枚举

异常枚举中存放着所有异常的状态码和信息

交验通过调用userService中的register注册接口

注册接口实现内容要先查询交验用户名是否为存在,如果存在直接抛出自定义的通用异常即可

自定义的通用异常接收异常枚举,每次要抛出不同的异常信息定义异常枚举传入再抛出即可

如果用户名不存在正常注册

UserMapper中定义selectByName查询用户名,返回user对象

转到mapper.xml书写sql语句

userMapper.insertSelective(user)方法是插入user中不为空的数据,该方法会返回一个数字代表修改了几条数据

判断如果返回的书==0,则插入失败,抛出自定义的数据插入失败自定义异常类并传入异常枚举

回到控制类,返回自定义的通用返回对象成功ApiRestResponse.success()(如果此前失败了则不会执行到此,直接被抛出异常了)

使用Postman测试post接口

统一处理异常

目的是对前端结构统一保证安全,因为post请求一个接口如果出现异常可能返回许多不同的参数

抛出异常,直接转化为Json的APIResponse

抛出重名异常

之前的请求返回
在这里插入图片描述

统一异常后的返回
在这里插入图片描述

GlobalExceptionHandler.java 开发过滤器处理异常

package com.learn2333.freshmall.exception;

import com.learn2333.freshmall.common.ApiRestResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * 处理统一异常的handler
 */
@ControllerAdvice
public class GlobalExceptionHandler {
    private final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    @ExceptionHandler(Exception.class)
    @ResponseBody
    public Object handleException(Exception e) {
        log.error("Default Exception: ", e);
        return ApiRestResponse.error(MallExceptionEnum.SYSTEM_ERROR);
    }

    @ExceptionHandler(MallException.class)
    @ResponseBody
    public Object handleMallException(MallException e) {
        log.error("MallException: ", e);
        return ApiRestResponse.error(e.getCode(), e.getMessage());
    }
}

自定义异常类

package com.learn2333.freshmall.exception;

/**
 * 统一异常
 */
 //了解完下面java异常体系后,可知道这里继承可将Exception改为RuntimeException运行时异常,因为这里要抛出的都是我们自定义的异常枚举,这样我们抛出异常的时候就不用再每次都增加方法签名了,而作用上一样的
public class MallException extends RuntimeException {
    private final Integer code;
    private final String message;

    public MallException(Integer code, String msg) {
        this.code = code;
        this.message = msg;
    }

    public MallException(MallExceptionEnum exceptionEnum) {
        this(exceptionEnum.getCode(), exceptionEnum.getMsg());
    }

get方法
}

根据程序开发过程需要增加自定义的异常枚举信息来配合异常类抛出

package com.learn2333.freshmall.exception;

/**
 * 异常枚举
 */
public enum MallExceptionEnum {
    NEED_USER_NAME(10001, "用户名不能为空"),
    NEED_PASSWORD(10002, "密码不能为空"),
    PASSWORD_TOO_SHORT(10003, "密码长度不能小于8位"),
    NAME_EXISTED(10004, "注册失败,不允许重名"),
    INSERT_FAILED(10005, "数据插失败入"),
    WRONG_PASSWORD(10006, "密码错误"),
    NEED_LOGIN(10007, "用户未登录"),
    UPDATE_FAILED(10008, "更新失败"),
    NEED_ADMIN(10009, "无管理员权限"),
    SYSTEM_ERROR(20000, "系统异常");
    Integer code;
    String msg;
    MallExceptionEnum(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }

get,set方法
}

通过统一返回对象类处理抛出的异常枚举信息并返回失败数据

package com.learn2333.freshmall.common;

import com.learn2333.freshmall.exception.MallExceptionEnum;

/**
 * 通用返回对象
 */
public class ApiRestResponse<T> {
    //状态码
    private Integer status;
    //信息
    private String msg;
    //范型的data
    private T data;
    //正常的状态码
    private static final int OK_CODE = 10000;
    //信息
    private static final String OK_MSG = "SUCCESS";

    public ApiRestResponse(Integer status, String msg, T data) {
        this.status = status;
        this.msg = msg;
        this.data = data;
    }

    public ApiRestResponse(Integer status, String msg) {
        this.status = status;
        this.msg = msg;
    }

    public ApiRestResponse() {
        this(OK_CODE, OK_MSG);
    }
    //成功 返回默认状态码(无参构造函数的2个常量)
    public static <T>  ApiRestResponse<T> success() {
        return new ApiRestResponse<>();
    }
    //成功 返回默认状态码和数据
    public static <T> ApiRestResponse<T> success(T result) {
        ApiRestResponse<T> response = new ApiRestResponse<>();
        response.setData(result);
        return response;
    }

    //失败 传入状态码和信息
    public static <T> ApiRestResponse<T> error(Integer code, String msg) {
        return new ApiRestResponse<>(code, msg);
    }

    //失败 传入定义的异常枚举
    public static <T> ApiRestResponse<T> error(MallExceptionEnum ex) {
        return new ApiRestResponse<>(ex.getCode(), ex.getMsg());
    }
    @Override
    public String toString() {
get,set;

Java异常体系

在这里插入图片描述

案例:登录接口

功能分析

登录状态要保持

session保存用户信息的实现方案

之后的访问,会先从session中获取用户信息,然后在执行业务逻辑

总结:

定义返回统一响应对象ApiRestResponse

登录状态使用session保持

统一异常处理,自定义异常枚举从底层不断向上抛出,使用ApiRestResponse返回异常信息

常见错误:

响应对象不规范(返回参数不一致等)

异常不统一处理,存在安全隐患

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

摘星喵Pro

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值