第四节——组件设计
执键写春秋 570 1

4. 组件设计

组件包括MD5加密、图片重命名、图片上传配置、全局常量以及异常枚举、自定义异常和全局异常处理。

4.1 工具类

4.1.1 MD5加密类【MD5Utils】

列举了三种生成方式,项目里使用的是方法一。

package pers.xsc.online_shopping.utils;

import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.util.ByteSource;
import org.apache.tomcat.util.codec.binary.Base64;
import org.springframework.util.DigestUtils;

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

/**
 * 密码加密工具类
 * 密码比较时只需将用户输入的密码再次转成MD5码与存储的相比较即可得知用户输入密码是否正确。
 */
public class MD5Utils {
    //方式一:通过Java自带的MessageDigest实现
    public static String getMD5StrByMessageDigest(String strValue) throws NoSuchAlgorithmException {
        MessageDigest md5 = MessageDigest.getInstance(Constant.ALGORITHM_NAME);
        return Base64.encodeBase64String(md5.digest((strValue + Constant.pwd_salt).getBytes()));
    }

    //方式二:通过Spring中的DigestUtils工具类
    public static String getMD5StrByDigestUtils(String strValue) {
        return DigestUtils.md5DigestAsHex((strValue + Constant.pwd_salt).getBytes());
    }

    //方式三:使用Shiro的SimpleHash加密密码工具类:需要添加shiro-core依赖
    /**
     * algorithmName:加密形式(具体支持哪些算法,请自行百度)
     * source:简单理解就是传入的原始明文密码值
     * salt:盐值
     * hashIterations:加密次数
     * 最终得到加密的密码 = MD5(明文密码 + 盐值)* 加密次数
     */
    public static String getMD5StrBySimpleHash(String strValue) {
        return new SimpleHash(Constant.ALGORITHM_NAME, strValue, ByteSource.Util.bytes(Constant.pwd_salt), Constant.HASH_ITERATIONS).toHex();
    }

    //测试
    public static void main(String[] args) throws NoSuchAlgorithmException {
        String pwd = getMD5StrByMessageDigest("123456");
        System.out.println(pwd);
        String pwd2 = getMD5StrByDigestUtils("123456");
        System.out.println(pwd2);
        String pwd3 = getMD5StrBySimpleHash("123456");
        System.out.println(pwd3);
    }
}

4.1.2 全局常量类【Constant】

package pers.xsc.online_shopping.utils;

/**
 * 常量类
 */
public class Constant {

    // 加密形式
    public static final String ALGORITHM_NAME = "MD5";

    // 加密次数
    public static final int HASH_ITERATIONS = 128;

    //MD5加密盐值
    public static final String pwd_salt = "hfg6594ha36546/*--*634" ;

    //验证码参数-生成元素
    public static final char CODE[] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
            'k', 'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y',
            'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M',
            'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '2',
            '3', '4', '5', '6', '7', '8', '9' };
    //生成宽度
    public static final int WIDTH = 50; 
    //生成高度
    public static final int HEIGHT = 20; 
    //生成字符数
    public static final int LENGTH = 4;  

    //前台用户session名
    public static final String CURRENT_USER = "currentUser";

    //后台管理员session名
    public static final String ADMIN_USER = "adminUser";

}

4.1.3 图片重命名类(带后缀)【ReFilenameUtils】

package pers.xsc.online_shopping.utils;


import org.apache.commons.lang.StringUtils;

import java.text.SimpleDateFormat;
import java.util.Calendar;

public class ReFilenameUtils {
    /**
     * 文件重命名(带后缀)
     * @param fileName 原文件名
     * @return 新文件名
     */
    public static String replaceFileName(String fileName) {
        StringBuilder builder = new StringBuilder();
        if (StringUtils.isNotEmpty(fileName)) {
            int index = fileName.lastIndexOf(".");
            if (index > 0) {
                SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmssSSS");
                String fileType = fileName.substring(index);// 文件后缀名
                Calendar cal = Calendar.getInstance();//获取当前的时间
                builder.append(format.format(cal.getTime()));
                builder.append(fileType);
            }
        }
        return builder.toString();
    }

    //测试
    public static void main(String[] args) {
        System.out.println(replaceFileName("hello.java"));
    }

}

4.1.4 图片上传配置类【UploadConfig】

用于解决springboot图片上传本地后需要重启服务器才能加载到图片的问题:

package pers.xsc.online_shopping.utils;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
@Configuration
public class UploadConfig extends WebMvcConfigurerAdapter {
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
//映射图片保存地址
        registry.addResourceHandler("/images/**").addResourceLocations("file:F:/online_shopping/online_shopping/src/main/resources/static/images/");
    }
}

4.1.5 自定义结果类【ResultUtils】

package pers.xsc.online_shopping.utils;

import pers.xsc.online_shopping.exception.ExceptionEnum;

public class ResultUtils {

    private Integer status; //状态码

    private String msg; //异常描述

    private Object data; //返回数据

    public ResultUtils(Integer status, String msg, Object data) {
        this.status = status;
        this.msg = msg;
        this.data = data;
    }

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

    public Integer getStatus() {
        return status;
    }

    public void setStatus(Integer status) {
        this.status = status;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    public ResultUtils(ExceptionEnum exceptionEnum){
        this.status = exceptionEnum.getCode();
        this.msg = exceptionEnum.getMsg();
    }

    public static ResultUtils success(){
        ResultUtils resultUtils = new ResultUtils(ExceptionEnum.SUCCESS);
        return resultUtils;
    }

    public static ResultUtils success(Object data){
        ResultUtils resultUtils = new ResultUtils(ExceptionEnum.SUCCESS);
        resultUtils.setData(data);
        return resultUtils;
    }

    public static ResultUtils error(){
        ResultUtils resultUtils = new ResultUtils(ExceptionEnum.SYSTEM_ERROR);
        return resultUtils;
    }
    public static ResultUtils error(Integer code, String msg) {
        return new ResultUtils(code, msg);
    }
    public static ResultUtils error(ExceptionEnum exceptionEnum){
        ResultUtils resultUtils = new ResultUtils(exceptionEnum);
        return resultUtils;
    }

    @Override
    public String toString() {
        return "信息提醒{" +
                "状态码=" + status +
                ",消息='" + msg + '\'' +
                ",数据=" + data +
                '}';
    }
}

4.2 组件类

4.2.1 验证码生成类【ValidateCodeController】

package pers.xsc.online_shopping.controller.before;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import pers.xsc.online_shopping.utils.Constant;

import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Random;

@Controller
public class ValidateCodeController {
    @RequestMapping("/validateCode")
    public void validateCode(HttpServletRequest request,
                             HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        // 设置响应报头信息
        response.setHeader("Pragma", "No-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expires", 0);
        // 设置响应的MIME类型
        response.setContentType("image/jpeg");

        BufferedImage image = new BufferedImage(Constant.WIDTH, Constant.HEIGHT,
                BufferedImage.TYPE_INT_RGB);
        Font mFont = new Font("Arial", Font.TRUETYPE_FONT, 18);
        Graphics g = image.getGraphics();
        Random rd = new Random();

        // 设置背景颜色
        g.setColor(new Color(rd.nextInt(55) + 200, rd.nextInt(55) + 200, rd
                .nextInt(55) + 200));
        g.fillRect(0, 0, Constant.WIDTH, Constant.HEIGHT);

        // 设置字体
        g.setFont(mFont);

        // 画边框
        g.setColor(Color.black);
        g.drawRect(0, 0, Constant.WIDTH - 1, Constant.HEIGHT - 1);

        // 随机产生的验证码
        String result = "";
        for (int i = 0; i < Constant.LENGTH; ++i) {
            result += Constant.CODE[rd.nextInt(Constant.CODE.length)];
        }
        HttpSession se = request.getSession();
        se.setAttribute("rand", result);

        // 画验证码
        for (int i = 0; i < result.length(); i++) {
            g.setColor(new Color(rd.nextInt(200), rd.nextInt(200), rd
                    .nextInt(200)));
            g.drawString(result.charAt(i) + "", 12 * i + 1, 16);
        }

        // 随机产生2个干扰线
        for (int i = 0; i < 2; i++) {
            g.setColor(new Color(rd.nextInt(200), rd.nextInt(200), rd
                    .nextInt(200)));
            int x1 = rd.nextInt(Constant.WIDTH);
            int x2 = rd.nextInt(Constant.WIDTH);
            int y1 = rd.nextInt(Constant.HEIGHT);
            int y2 = rd.nextInt(Constant.HEIGHT);
            g.drawLine(x1, y1, x2, y2);
        }

        // 释放图形资源
        g.dispose();
        try {
            OutputStream os = response.getOutputStream();

            // 输出图像到页面
            ImageIO.write(image, "JPEG", os);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

4.2.2 异常枚举类【ExceptionEnum】

package pers.xsc.online_shopping.exception;

/**
 * 异常枚举
 */
public enum ExceptionEnum {
    SYSTEM_ERROR(00000, "系统异常,请从控制台或日志中查看具体错误信息"),
    SUCCESS(10000,"成功!"),

    NEED_LOGIN(20001, "用户未登录"),
    USER_LOGIN_ERROR(20002, "账号不存在或密码错误"),
    PARAM_IS_BLANK(20003,"参数[用户名/密码]为空"),
    OBJECT_IS_BLANK(20004,"对象为空"),
    SESSION_FAILED(20005,"session失效,须重新登录"),

    REQUEST_PARAM_ERROR(30001,"参数错误"),

    INSERT_ERROR(40001,"数据添加失败");


    private Integer code;
    private String msg;

    public Integer getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }

    ExceptionEnum(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    @Override
    public String toString() {
        return "ExceptionEnum{" +
                "code=" + code +
                ", msg='" + msg + '\'' +
                '}';
    }
}

4.2.3 自定义异常类【CustomException】

package pers.xsc.online_shopping.exception;

public class CustomException extends  RuntimeException{
    private Integer code;
    private String message;

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    @Override
    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

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

4.2.4 全局异常处理类【ExceptionHandle】

package pers.xsc.online_shopping.exception;

import jdk.internal.org.objectweb.asm.tree.analysis.Value;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import pers.xsc.online_shopping.utils.ResultUtils;

import java.util.ArrayList;
import java.util.List;

@Slf4j
@ControllerAdvice
public class ExceptionHandle {
    @ExceptionHandler(value = Exception.class)
    public String  handleException(Exception e , Model model){
        log.info("Exception",e);
        model.addAttribute("errorMessage",ResultUtils.error(ExceptionEnum.SYSTEM_ERROR).toString());
        return "Error";
    }
    //处理自定义的异常
    @ExceptionHandler(value = CustomException.class)
    public String  handleCustomException(CustomException e , Model model){
        log.info("CustomException",e);
        model.addAttribute("errorMessage",ResultUtils.error(e.getCode(),e.getMessage()).toString());
        return "Error";
    }
    //注解参数校验异常
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public String  handleMethodArgumentNotValidException(MethodArgumentNotValidException e , Model model){
        log.info("MethodArgumentNotValidException",e);
        model.addAttribute("errorMessage",handleBindingResult(e.getBindingResult()).toString());
        return "Error";

    }
    private ResultUtils handleBindingResult(BindingResult result) {
        //把异常处理为对外暴露的提示
        List<String> list = new ArrayList<>();
        if (result.hasErrors()) {
            List<ObjectError> allErrors = result.getAllErrors();
            for (ObjectError objectError : allErrors) {
                String message = objectError.getDefaultMessage();
                list.add(message);
            }
        }
        if (list.size() == 0) {
            return ResultUtils.error(ExceptionEnum.REQUEST_PARAM_ERROR);
        }
        return ResultUtils.error(ExceptionEnum.REQUEST_PARAM_ERROR.getCode(), list.toString());
    }
}

4.2.5 用户过滤器类【UserFilter】

package pers.xsc.online_shopping.utils;

import pers.xsc.online_shopping.entity.User;
import pers.xsc.online_shopping.exception.CustomException;
import pers.xsc.online_shopping.exception.ExceptionEnum;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;

public class UserFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        Filter.super.init(filterConfig);
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpSession session = request.getSession();
        User currentUser = (User) session.getAttribute(Constant.CURRENT_USER);
        try{
            if (currentUser == null) {
                throw new CustomException(ExceptionEnum.NEED_LOGIN.getCode(),ExceptionEnum.NEED_LOGIN.getMsg());
            }else{
                filterChain.doFilter(servletRequest, servletResponse);
            }
        }catch(CustomException e){
            request.setAttribute("filter.error", ExceptionEnum.NEED_LOGIN);
            request.getRequestDispatcher("/myError").forward(request, servletResponse);
        }
    }

    @Override
    public void destroy() {
        Filter.super.destroy();
    }
}

4.2.5 用户过滤器配置类【UserFilterConfig】

package pers.xsc.online_shopping.utils;

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class UserFilterConfig {
    @Bean
    public UserFilter userFilter() {
        return new UserFilter();
    }

    @Bean(name = "userFilterConf")
    public FilterRegistrationBean adminFilterConfig() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(userFilter());
        filterRegistrationBean.addUrlPatterns("/focus/myFocus");
        filterRegistrationBean.addUrlPatterns("/user/userInfo");
        filterRegistrationBean.addUrlPatterns("/cart/selectCart");
        return filterRegistrationBean;
    }
}

4.2.6 捕获过滤器中产生异常类【MyErrorController】

package pers.xsc.online_shopping.controller.before;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import pers.xsc.online_shopping.exception.CustomException;
import pers.xsc.online_shopping.exception.ExceptionEnum;

import javax.servlet.http.HttpServletRequest;

@Controller
public class MyErrorController {
    @RequestMapping("/myError")
    public void error(HttpServletRequest request){
        ExceptionEnum e = (ExceptionEnum) request.getAttribute("filter.error");
        throw new CustomException(e.getCode(),e.getMsg());
    }
}
评论区

索引目录