SpringBoot电商后台开发项目总结(1)

基于SpringBoot开发的后台管理、系统脚手架Github\Gitee收集 GitHub: 项目基于 Spring Boot 2.1.0 、 Jpa、 Spring Security、redis、Vue的前后端分离的后台管理系统 项目简介eladmin基于 Spring Boot 2.1.0 、 Jpa、 Spring Security、redis、Vue的前后端分离的后台管理系统, 权限控制的方式为RBAC,项目支持数据字典与数据权限管理,支持一键生成前后端代码,支持... 阅读详情

这篇文章是无关业务逻辑代码的基础配置

最近学习java项目开发,对springboot项目进行总结,该文章是对于非业务代码的总结

一、相关配置

1. 数据库相关配置

根据Mybatis-generator插件生成对应的实体类与Mapper

pom.xml配置

        <plugin>
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
                <version>1.3.7</version>
                <configuration>
                    <verbose>true</verbose>
                    <overwrite>true</overwrite>
                </configuration>
            </plugin>

首先得有配置文件generatorConfig.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
    <!-- 配置文件,放在resource目录下即可 -->
    <!--数据库驱动个人配置,此处遵循mvn的下载地址-->
    <classPathEntry location="maven-repo\mysql\mysql-connector-java\8.0.18\mysql-connector-java-8.0.18.jar"/>
    <context id="MysqlTables" targetRuntime="MyBatis3">
        <property name="autoDelimitKeywords" value="true"/>
        <!--可以使用``包括字段名,避免字段名与sql保留字冲突报错-->
        <property name="beginningDelimiter" value="`"/>
        <property name="endingDelimiter" value="`"/>
        <!-- optional,旨在创建class时,对注释进行控制 -->
        <commentGenerator>
            <property name="suppressDate" value="true"/>
            <property name="suppressAllComments" value="true"/>
        </commentGenerator
 <!--数据库链接地址账号密码-->
        <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
           connectionURL="jdbc:mysql://127.0.0.1:3306/imooc_mall?useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=Asia/Shanghai&amp;zeroDateTimeBehavior=convertToNull"
                        userId="root" password="123456">
    <property name="nullCatalogMeansCurrent" value="true"/>
        </jdbcConnection>
        <!-- 非必需,类型处理器,在数据库类型和java类型之间的转换控制-->
        <javaTypeResolver>
            <property name="forceBigDecimals" value="false"/>
        </javaTypeResolver>
        <!--生成Model类存放位置-->
        <javaModelGenerator targetPackage="com.imooc.mall.model.pojo"
                            targetProject="src/main/java">
            <!-- 是否允许子包,即targetPackage.schemaName.tableName -->
            <property name="enableSubPackages" value="true"/>
            <!-- 是否对类CHAR类型的列的数据进行trim操作 -->
            <property name="trimStrings" value="true"/>
      <!-- 建立的Model对象是否 不可改变  即生成的Model对象不会有 setter方法,只有构造方法 -->
            <property name="immutable" value="false"/>
        </javaModelGenerator>
     <!--生成mapper映射文件存放位置-->
        <sqlMapGenerator targetPackage="mappers" targetProject="src/main/resources">
            <property name="enableSubPackages" value="true"/>
        </sqlMapGenerator>
      <!--生成Dao类存放位置-->
        <javaClientGenerator type="XMLMAPPER" targetPackage="com.imooc.mall.model.dao"
                             targetProject="src/main/java">
            <property name="enableSubPackages" value="true"/>
        </javaClientGenerator>
        <!--生成对应表及类名-->
        <table schema="root" tableName="imooc_mall_cart" domainObjectName="Cart"
               enableCountByExample="false"
               enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false"
               selectByExampleQueryId="false">
        </table>
        <table tableName="imooc_mall_category" domainObjectName="Category" enableCountByExample="false"
               enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false"
               selectByExampleQueryId="false">
        </table>
        <table tableName="imooc_mall_order" domainObjectName="Order" enableCountByExample="false"
               enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false"
               selectByExampleQueryId="false">
        </table>
        <table tableName="imooc_mall_order_item" domainObjectName="OrderItem"
               enableCountByExample="false"
               enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false"
               selectByExampleQueryId="false">
        </table>
        <table tableName="imooc_mall_product" domainObjectName="Product" enableCountByExample="false"
               enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false"
               selectByExampleQueryId="false">
        </table>
        <table tableName="imooc_mall_user" domainObjectName="User" enableCountByExample="false"
               enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false"
               selectByExampleQueryId="false">
        </table>

    </context>
</generatorConfiguration>

然后如下图双击生成实体类型以及xml和DAO接口

在application.properties中配置数据库

指明mappers的位置

spring.datasource.name=imooc_mall_datasource
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/imooc_mall?useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false&serverTimezone=Asia/Shanghai
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=123456
mybatis.mapper-locations=classpath:mappers/*.xml

打通Controller到service到DAO层(测试)

需要在主函数上配置basePackages说明DAO在那里

  如果测试正确就代表数据库配置完成。

2.日志系统相关配置

移除logback 使用log4j配置pom.xml

   <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!--log4j2日志依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-log4j2</artifactId>
   </dependency>

引入log4j包后需要配置log4j2.xml

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="fatal">
    <Properties>
        <!--   value中是所包含存储日志的地方-->
        <Property name="baseDir" value="D:/logs/mallLog"/>
    </Properties>

    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch) -->
            <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout
                    pattern="[%d{MM:dd HH:mm:ss.SSS}] [%level] [%logger{36}] - %msg%n"/>
        </Console>

        <!--debug级别日志文件输出-->
        <RollingFile name="debug_appender" fileName="${baseDir}/debug.log"
                     filePattern="${baseDir}/debug_%i.log.%d{yyyy-MM-dd}">
            <!-- 过滤器 -->
            <Filters>
                <!-- 限制日志级别在debug及以上在info以下 -->
                <ThresholdFilter level="debug"/>
                <ThresholdFilter level="info" onMatch="DENY" onMismatch="NEUTRAL"/>
            </Filters>
            <!-- 日志格式 -->
            <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
            <!-- 策略 -->
            <Policies>
                <!-- 每隔一天转存 -->
                <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
                <!-- 文件大小 -->
                <SizeBasedTriggeringPolicy size="100 MB"/>
            </Policies>
        </RollingFile>

        <!-- info级别日志文件输出 -->
        <RollingFile name="info_appender" fileName="${baseDir}/info.log"
                     filePattern="${baseDir}/info_%i.log.%d{yyyy-MM-dd}">
            <!-- 过滤器 -->
            <Filters>
                <!-- 限制日志级别在info及以上在error以下 -->
                <ThresholdFilter level="info"/>
                <ThresholdFilter level="error" onMatch="DENY" onMismatch="NEUTRAL"/>
            </Filters>
            <!-- 日志格式 -->
            <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
            <!-- 策略 -->
            <Policies>
                <!-- 每隔一天转存 -->
                <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
                <!-- 文件大小 -->
                <SizeBasedTriggeringPolicy size="100 MB"/>
            </Policies>
        </RollingFile>

        <!-- error级别日志文件输出 -->
        <RollingFile name="error_appender" fileName="${baseDir}/error.log"
                     filePattern="${baseDir}/error_%i.log.%d{yyyy-MM-dd}">
            <!-- 过滤器 -->
            <Filters>
                <!-- 限制日志级别在error及以上 -->
                <ThresholdFilter level="error"/>
            </Filters>
            <!-- 日志格式 -->
            <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
            <Policies>
                <!-- 每隔一天转存 -->
                <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
                <!-- 文件大小 -->
                <SizeBasedTriggeringPolicy size="100 MB"/>
            </Policies>
        </RollingFile>
    </Appenders>
    <Loggers>
        <Root level="debug">
            <AppenderRef ref="Console"/>
            <AppenderRef ref="debug_appender"/>
            <AppenderRef ref="info_appender"/>
            <AppenderRef ref="error_appender"/>
        </Root>

    </Loggers>
</Configuration>

然后配置截断器,也就是一切流量都会经过日志,新建Filter目录下WebLogAspect.xml

package com.imooc.mall.Filter;


import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;

@Aspect
@Component
public class WebLogAspect {

    private final Logger log = LoggerFactory.getLogger(WebLogAspect.class);
     //经过控制器的所有流量
    @Pointcut("execution(public * com.imooc.mall.Controller.*.*(..))")
    public void webLog() {
    }
    @Before("webLog()")
     //请求发生之前
    public  void doBefore(JoinPoint joinPoint)
    {
        ServletRequestAttributes requestAttributes =                 (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        log.info("URL: "+request.getRequestURI().toString());
        log.info("HTTP_METHOD: "+request.getMethod());
        log.info("IP: "+request.getRemoteAddr());
        log.info("CLASS_METHOD" + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        log.info("ARGS :" + Arrays.toString(joinPoint.getArgs()));
    }
     //请求发生以后
    
    @AfterReturning(returning = "res", pointcut = "webLog()")
    public void doAfterReturning(Object res) throws JsonProcessingException {
        //处理完请求,返回内容
        log.info("RESPONSE :" + new ObjectMapper().writeValueAsString(res));

    }


}

二、开发框架搭建

1.设置返回接口标准类

接口需要返回状态代码code,以及返回成功与否msg,成功时需要携带得数据data:

由于data得类型不确定所

package com.imooc.mall.common;
import com.imooc.mall.Exception.MallExceptionEnum;
public class ApiRestResponse<T> {
    private Integer status;
    private String  msg;
    private T data;
    private static final  int OK_CODE = 1000;
    private static final  String OK_MSG="success";

    /*不返回data时,使用的构造函数*/
    ApiRestResponse(Integer status,String msg)
    {
        this.status = status;
        this.msg = msg;
    }

    ApiRestResponse(Integer status,String msg,T data)
    {
        this.status = status;
        this.msg = msg;
        this.data = data;
    }
    public ApiRestResponse() {
        this(OK_CODE, OK_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 T getData() {
        return data;
    }

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

    /**
     * 请求成功 data=null
     * @return
     */

    public static <T> ApiRestResponse<T> success()
    {
        return new ApiRestResponse<>();
    }

    /**
     * 请求成功
     * @param result data数据
     * @param <T>
     * @return
     */

    public static <T> ApiRestResponse<T> success(T result)
    {
        ApiRestResponse<T> arr = new ApiRestResponse<>();
        arr.setData(result);
        return  arr;
    }

    /**
     * 请求失败
     * @param status
     * @param msg
     * @param <T>
     * @return
     */

    public static <T> ApiRestResponse<T> fail(Integer status ,String msg)
    {
        return new ApiRestResponse<>(status,msg);

    }
    /*与自定义的异常搭配使用*/

    public static <T> ApiRestResponse<T> error(MallExceptionEnum ex)
    {
        return  new ApiRestResponse<>(ex.getCode(),ex.getMsg());
    }

}

2.自定义异常枚举类

异常枚举类是定义在程序运行过程中需要处理的异常类型

package com.imooc.mall.Exception;

public enum MallExceptionEnum {
    NEED_USER_NAME(10001,"用户名不能空"),
    NEED_PASSWORD(10002,"密码不能为空"),
    PASSWORD_TOO_SHORT(10003,"密码长度不能小于8位"),
    NAME_EXIST(10004,"名称已经存在"),
    INSERT_FAIL(10005,"用户注册失败"),
    LOGIN_FAIL(10007,"用户名或者密码错误"),
    NEED_LOGIN(10008,"用户未登录"),
    UPDATE_FAILED(10009,"更新失败"),
    NEED_ADMIN(10010,"非管理员用户"),
    NAME_NOT_NULL(10011,"参数不能为空"),
    PARAM_ERROR(10012,"参数不合法"),
    DELETE_ERROR(10013,"删除失败"),
    PARAM_NOT_EXIST(10014,"缺失参数"),
    MKDIR_FAILED(10015,"文件夹创建失败"),
    UPLOAD_FAIL(10016,"文件上传失败"),
    PRODUCT_NOT_EXISTED(10017,"该商品不可售出"),
    NOT_ENOUGH(10018,"商品库存不足"),
    CART_SELECTED_EMPTY(10019,"购物车勾选商品为空"),
    ORDER_NOT_EXISTED(10020,"订单不存在"),
    NOT_YOU(10021,"未授权访问"),
    NOT_ENUM(10022,"不存在此代码"),
    WRONG_ORDER_STATUS(10023,"当前订单状态不为未支付"),
    USERNAME_NOT_EXISTED(10024,"用户名不能更改"),
    SYSTEM_ERROR(20001,"系统错误");

/*
   code 是API接口返回的code
    msg 是API接口返回的msg
*/
    Integer code;
    String msg;

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

    public Integer getCode() {
        return code;
    }

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

    public String getMsg() {
        return msg;
    }

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

3. 自定义异常处理类

Service层在进行操作时会产生各种异常,我们需要将异常统一归类,方便全局处理

package com.imooc.mall.Exception;

public class MallException extends Exception{

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

    }
    public MallException(MallExceptionEnum exceptionEnum)
    {
        this.code =exceptionEnum.getCode();
        this.msg = exceptionEnum.getMsg();
    }

    public Integer getCode() {
        return code;
    }

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

    public String getMsg() {
        return msg;
    }

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

这里存在两种初始化,实际上用得多的是第二种类型。

4. 全局异常处理类

package com.imooc.mall.Exception;

import com.imooc.mall.Annotation.OperationLogAnnotation;
import com.imooc.mall.common.ApiRestResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

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

/*ControllerAdvice 全局Controller异常接受*/
@ControllerAdvice
public class GlobalExceptionHandler {
        private final Logger log=LoggerFactory.getLogger(GlobalExceptionHandler.class);

        @ExceptionHandler(Exception.class)
        @ResponseBody
        public ApiRestResponse handleException(Exception e){
            log.error("System Exception:",e);
            return ApiRestResponse.error(MallExceptionEnum.SYSTEM_ERROR);
        }
        @ExceptionHandler(MallException.class)
        @ResponseBody
        public ApiRestResponse handleMallException(MallException e){
            log.error("Projection Exception:",e);
            return ApiRestResponse.fail(e.getCode(),e.getMsg());
        }
        @ExceptionHandler(MethodArgumentNotValidException.class)
        @ResponseBody
        public ApiRestResponse handleVaildException(MethodArgumentNotValidException e)
        {
            log.error("MethodArgumentNotValidException:",e);
            return handleBindingResult(e.getBindingResult());
        }
        private ApiRestResponse handleBindingResult(BindingResult result) {

        List<String> list = new ArrayList<>();
        if (result.hasErrors()) {//如果BindingResult中,包含错误,就获取其中所有的错误信息;
            List<ObjectError> allErrors = result.getAllErrors();
            //遍历所有的错误信息;
            for (int i = 0; i < allErrors.size(); i++) {
                ObjectError objectError = allErrors.get(i);
                //提取具体的错误信息;
                String message = objectError.getDefaultMessage();
                //将错误信息,添加到list集合中
                list.add(message);
            }
        }
        if (list.size() == 0) {
            return ApiRestResponse.error(MallExceptionEnum.PARAM_ERROR);
        }
        //根据MethodArgumentNotValidException异常的具体错误信息,构建ApiRestResponse统一返回对象;
        return ApiRestResponse.fail(MallExceptionEnum.PARAM_ERROR.getCode(), list.toString());
    }
    @ExceptionHandler(MissingServletRequestParameterException.class)
    @ResponseBody
    public ApiRestResponse handleParamException(MissingServletRequestParameterException e)
    {
        log.error("MissingServletRequestParameterException:",e);
        return ApiRestResponse.error(MallExceptionEnum.PARAM_NOT_EXIST);

    }
}

@ControllerAdvice注解,用于对Controller层抛出的异常处理

我们这里处理了4种类型的异常

  • 系统异常
  • 自定义异常
  • 参数输入步骤缺,入如参数确实,参数为空
  • 参数有特定的范围时,输入不在此范围之类会抛出异常

三、全局校验

1. 全局常量参数

package com.imooc.mall.common;

import com.google.common.collect.Sets;
import com.imooc.mall.Exception.MallException;
import com.imooc.mall.Exception.MallExceptionEnum;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;


import java.util.Set;

@Component
public class Constant {
    public static  final String salt = "hasu9fhdsiofjiosa}{x";
    public static  final String MALL_USER = "mall_user";
    public static  String FILE_UPLOAD_DIR;
    @Value("${file.upload.dir}")
    public void setFileUploadDir(String fileUploadDir){FILE_UPLOAD_DIR = fileUploadDir;}
    public interface ProductListOrderBy
    {
        Set<String> PRICE_ASC_DESC = Sets.newHashSet("price desc","price asc");
    }
    public enum OrderStatusEnum
    {
        CANCELED(0, "用户已取消"),
        NOT_PAY(10, "未付款"),
        PAID(20,"已付款"),
        DELIVERED(30,"已发货"),
        FINISHED(40,"交易完成");
        private int code;
        private String value;

        OrderStatusEnum(int code, String value) {
            this.code = code;
            this.value = value;
        }

        public static String codeOf(int code) throws MallException{
            for(OrderStatusEnum ose:values())
            {
                if(ose.getCode()==code)
                {
                    return ose.getValue();
                }
            }
            throw new MallException(MallExceptionEnum.NOT_YOU);
        }

        public int getCode() {
            return code;
        }

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

        public String getValue() {
            return value;
        }

        public void setValue(String value) {
            this.value = value;
        }
    }
}

全局参数包括:

  • 盐值
  • session存储参数
  • 文件上传存储位置
  • order by 排序类型
  • 订单状态枚举

2. 用户身份校验

package com.imooc.mall.Filter;


import com.imooc.mall.common.Constant;
import com.imooc.mall.model.pojo.User;

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

public class UserFilter implements Filter {
    public static User currentuser;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request= (HttpServletRequest)servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        currentuser =   (User)request.getSession().getAttribute(Constant.MALL_USER);
        if(currentuser==null){
            PrintWriter out  = new HttpServletResponseWrapper(response).getWriter();
            out.write(
                    "{\n" +
                            "    \"status\": 10008,\n" +
                            "    \"msg\": \"NEED LOGIN\",\n" +
                            "    \"data\": null\n" +
                            "}"

            );
            out.flush();
            out.close();
            return;
        }
        filterChain.doFilter(servletRequest,servletResponse);
    }

    @Override
    public void destroy() {

    }
}

其中Constant类是用来定义常量的,会话管理的方法是利用java原生的session

3. 管理员权限校验

package com.imooc.mall.Filter;

import com.imooc.mall.common.Constant;
import com.imooc.mall.model.pojo.User;

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

public class AdminFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    /**
     * 统一身份认证接口
     * @param servletRequest
     * @param servletResponse
     * @param filterChain
     * @throws IOException
     * @throws ServletException
     */
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        HttpServletRequest request= (HttpServletRequest)servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        User currentuser = (User)request.getSession().getAttribute(Constant.MALL_USER);
        if(currentuser==null){
            PrintWriter out  = new HttpServletResponseWrapper(response).getWriter();
            out.write(
                    "{\n" +
                            "    \"status\": 10008,\n" +
                            "    \"msg\": \"NEED LOGIN\",\n" +
                            "    \"data\": null\n" +
                            "}"

            );
            out.flush();
            out.close();
        }
        if(currentuser.getRole().equals(2))
        {
            filterChain.doFilter(servletRequest,servletResponse);
        }
        else
        {
            PrintWriter out = new HttpServletResponseWrapper(response).getWriter();
            out.write("{\n" +
                    "    \"status\": 10010,\n" +
                    "    \"msg\": \"ADMIN NEED\",\n" +
                    "    \"data\": null\n" +
                    "}");
            out.flush();
            out.close();
            return;
}


    }

    @Override
    public void destroy() {

    }
}

四、全局校验配置

我们在(三)中设置了过滤器,必须在有相应的配置才能让spring知晓

1. 用户校验配置

package com.imooc.mall.Config;

import com.imooc.mall.Filter.UserFilter;
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 adminFilterConifg()
    {
        FilterRegistrationBean frb = new FilterRegistrationBean();
        frb.setFilter(userFilter());
        frb.addUrlPatterns("/user/*");
        frb.addUrlPatterns("/cart/*");
        frb.addUrlPatterns("/order/*");
        frb.setName("userFilterConf");
        return frb;
    }


}

2. 管理员校验配置

package com.imooc.mall.Config;

import com.imooc.mall.Filter.AdminFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AdminFilterConfig {
    @Bean
    public AdminFilter adminFilter()
    {
        return new AdminFilter();
    }
    @Bean(name="adminFilterConf")
    public FilterRegistrationBean adminFilterConifg()
    {
        FilterRegistrationBean frb = new FilterRegistrationBean();
        frb.setFilter(adminFilter());
        frb.addUrlPatterns("/admin/*");
        frb.setName("adminFilterConf");
        return frb;
    }
}

3. 文件存储实际位置与虚拟位置转化

package com.imooc.mall.Config;

import com.imooc.mall.common.Constant;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class MallWebConfig implements WebMvcConfigurer {
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry)
    {

        registry.addResourceHandler("/images/**").addResourceLocations("file:"+ Constant.FILE_UPLOAD_DIR);

    }

}

总结

 

springboot网上图书商城源码 bookstore电商书城系统说明 源码下载地址:https://gitee.com/chenshuai777/soft 目的: 在校学习,进一步熟悉Spring Boot开发模式,熟悉开发流程。本系统适用于JavaWeb初学者。 使用技术 后台主要是springboot+mybatis+shiro+jsp(jsp已过时)…,前端界面主要使用bootstrap框架搭建,并使用了ueditor富文本编辑器、highcharts图表库 系统划分与功能 该系统分为前台展示和后台管理两大模块。 前台主要是为消费者服 阅读详情

相关推荐

SpringBoot+vue项目实战

目录 前言: 技术准备 开发流程 项目展示 前言: 项目学习地址,点击了解:https://how2j.cn 天猫整站 Springboot 版本,就是这样一个实践项目。 我会带着大家,从零开始,把整个项目构建出来。成熟的项目规划与设计 本教程作者,也就是我~ 有8年企业开发管理经验,7年教学经验,曾参与管理开发几十个商业项目。将展示如何合理设计与规划这样一个规模的电商项目,既做到功能丰富,又让开发节奏有条不紊。基于Springboot 框架技术 本项目使用 Springboot 框架进行系统

java_zdc的博客 8697

【SpringBoot商城秒杀系统项目总结25】 项目的亮点和难点及问题解决(源码地址)

【商城限时秒杀系统总结】 在高并发情况下的秒杀优化,我们知道当并发数达到一定量的时候,会对数据库服务器带来很大的压力,那么如何缓解这些压力以及提高并发的QPS就是整个项目的解决重点,也是我们优化系统的目标。 项目的亮点与难点 1.使用分布式Seesion,可以实现让多台服务器同时可以响应。 2.使用redis做缓存提高访问速度和并发量,减少数据库压力,利用内存标记减少redis的访问。 3.使用页...

pitt1997的博客 2万+

基于Java+SpringBoot+Vue前后端分离电商项目【小米商城】

基于Java+SpringBoot+Vue前后端分离电商项目

luckypian 2649

SpringBoot项目总结

SpringBoot优点 快速创建独立运行的Spring项目以及与主流框架集成 使用嵌入式的Servlet容器,应用无需打成war包 starters自动依赖与版本控制 大量的自动配置,简化开发,也可修改默认值 无需配置xml,无代码生成,开箱即用 准生产环境的运行时应用监控 SpringBoot缺点 运维和部署难度大 微服务 微服务单元之间通过HTTP的方式进行轻量级通信 SpringBo...

weixin_44925211的博客 2332

AutoCAD Plant 3D自定义零件库实战:手把手教你用Python创建参数化槽式三通

本文详细介绍了如何利用Python脚本在AutoCAD Plant 3D中创建参数化槽式三通组件,从API原理到实战开发,帮助用户构建高效的自定义零件库。通过Python装饰器系统控制零件属性和行为,实现几何建模、参数管理和规格编辑器集成,提升工业管道设计的标准化和效率。

weixin_28267011的博客 329

手把手教你用STM32单片机控制双向可控硅调光(附完整代码+电路图)

本文提供了一套完整的STM32单片机控制双向可控硅实现灯光无级调光的实战方案。详细讲解了硬件电路设计,包括过零检测与隔离驱动,并剖析了基于定时器中断的软件核心逻辑,通过精准的相位角计算实现平滑的灯光强度控制。附有完整代码与电路图,适合嵌入式开发者实践。

weixin_29194255的博客 951

Spring Boot 总结

SpringBoot的知识点总结,有助于帮助您熟悉知识要点,加强记忆。

m0_59317114的博客 3231

AI虚拟人物 数字人直播,不用出镜,不用露脸的直播方式(附教程 软件)

我们先来看一组数据,这是我通过蝉妈妈查到的某位虚拟主播的一个带货数据,粉丝还不到 3000 人,每次直播 1 到 4 个小时,30天的总销量达到了1200单,15天,总销售额 2 万,可能相对来说客单价还是比较低,最关键的是才直播了 6 场,如果说他能够一个月直播 20 天,每天花 4个小时去直播,当个副业来做,就可以达到最起码月入 3 万的一个收入水平,我个人觉得是非常的不错的。大家把商品图片放在背景,只要场景设置的不错,场景和产品的关联度高,直播的时候挂上购买链接也会有一定的成交。

. 7万+

Springboot总结

springboot

xiaopang2020的博客 2136

(二)MS-MPI多机通信

1.关于MPI多机通信 一台计算机处理数据的能力是有限的,MPI的主要作用就是用来实现并行计算机,即将多台主机联机,实现大规模、高性能的计算机机群。我们知道一台计算机同时运行多个进程时,由于计算机资源是共享的,多个进程都会占用一些资源,每个进程运行的效率就会降低,比如当一台计算机同时跑着多个大型应用时会变得非常卡顿。所谓多机通信,可以理解为将本应该在同一台主机上运行的多个进程分配到多台主机上,以往...

xinwuya_的博客 4389

手把手教学:用国产GLM-4.6替代Claude4.0,实现AI自动化编程全流程

本文提供了一份详细的教程,指导开发者使用国产GLM-4.6模型替代Claude 4.0,实现AI自动化编程。内容涵盖从获取API密钥、搭建本地环境、改造Claude Code工具到实战开发与VSCode集成的全流程,旨在帮助用户低成本、高效率地体验AI自主编程。

weixin_29070861的博客 550

SpringBoot学习总结

目录 1、我的第一个SpringBoot项目 创建SpringBoot项目 如何修改端口号 2、SpringBoot自动装配原理 3、yaml语法 用yaml赋值 配置文件占位符 结论: 4、JSR303数据校验及多环境切换 5、整合JDBC,Druid,Mybatis 1.整合JDBC 2.整合Druid 3.整合Mybatis 6、SpringSecurity 实验环境搭建 认识SpringSecurity 认证和授权 1.引入 Spring Security 模块.

Melekh_的博客 3248

如何快速下载Gaia DR3星表数据?中国虚拟天文台镜像站保姆级教程

本文提供了一份详细的保姆级教程,指导用户如何通过中国虚拟天文台镜像站高速、稳定地下载Gaia DR3星表数据。文章详细介绍了镜像站的访问地址、数据组织结构,并给出了使用wget、aria2c等工具进行批量下载的实战策略,帮助国内用户避开国际网络延迟,高效获取近20亿颗天体的海量数据。

weixin_29231263的博客 296

springboot/java/php/node/python基于java电商后台管理系统【计算机毕设】

通过对该系统的研究,可以深入了解电商业务的运作模式和管理需求,为今后的电商项目提供有益的参考和借鉴。该系统的开发将有助于提高企业的运营效率,降低运营成本,提升客户满意度,从而为企业创造更大的经济效益。为了提高电商企业的运营效率,降低运营成本,提升客户满意度,开发一套基于Java的电商后台管理系统显得尤为重要。后端由Spring Boot提供支持,前端由Vue.js构建,数据存储和管理通过MySQL和Navicat实现,整个开发流程由Maven进行管理,并在Tomcat服务器上运行。

qih110的博客 299

llama.cpp量化模型在MTT显卡上的性能对比:S80/S3000/S4000实测数据

本文基于摩尔线程MTT S80、S3000和S4000三款显卡,对llama.cpp量化模型进行了深度性能实测。报告详细对比了不同量化精度(如Q4_K_M、Q6_K)在Llama 3.2 1B和Qwen 2.5 7B模型上的推理速度、显存占用、功耗及温度表现,为开发者根据硬件选择最优模型配置与参数调优提供了关键数据参考和实战指南。

week9的博客 349

ubuntu18.04 升级Ubuntu 20.04

Ubuntu 18.04升级20.04指南:首先备份重要数据,更新当前系统并检查新版本可用性(sudo do-release-upgrade -c)。确认升级后执行sudo do-release-upgrade,按提示完成操作。升级过程需耐心等待,完成后重启系统。注意:升级前务必备份数据,确保系统为最新版本,以降低风险。升级后即可使用Ubuntu 20.04系统。

https://ophome.blog.youkuaiyun.com,在IT行业有多年的工作经验,尤其是在Python、Linux、负载均衡、Nginx和服务器运维等领域。 1057

【程序源代码】Springboot2.1+花卷商城

“关键字:企业平台”正文:后台管理系统介绍Springboot2.1+花卷商城,一款基于 Springboot+Vue 的电商项目,前后端分离项目 使用框架 ...

程序源代码 442

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

java-net-php-python-springboot电商后台管理系统查重PPT计算机毕业设计程序

java-net-php-python-springboot电商后台管理系统查重PPT计算机毕业设计程序。springboot基于springboot的学生社团管理系统的研究设计。ssm基于Java智能选课系统的设计与实现。ssm基于SSM框架的学习资料校内共享平台。springboot奥利给共享自习室系统。springboot在线课程教学大纲系统。springboot便行顺风车出行系统。

m0_72148691的博客 307

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

Spring Boot电商项目

Spring Boot电商项目一.概述1.电商项目整体介绍(1)前台模块具体分析(2)后台模块具体分析(3) 项目演示2 . 项目开发所需工具准备二. 数据库设计于项目初始化1.表设计2. 项目的初始化3.配置log4j2日志组件4. AOP统一处理web请求日志三.用户模块的开发1.用户模块整体介绍2.API统一返回对象3.注册接口的开发4.对密码进行MD5保护5.登录、登出、更新接口的开发四.商品分类管理模块的开发1.分类模块地主要功能2.后台新增分类功能的实现3. 使用@Valid注解进行参数校验4.

weixin_50216991的博客 6956

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

SpringBoot实战项目收藏(都是超级好的)

mall Github地址:https://github.com/macrozheng/mall star: 22.9k 介绍: mall项目是一套电商系统,包括前台商城系统及后台管理系统,基于SpringBoot+MyBatis实现。 前台商城系统包含首页门户、商品推荐、商品搜索、商品展示、购物车、订单流程、会员中心、客户服务、帮助中心等模块。 后台管理系统包含商品管理、订单管理、会员管...

jeason的博客 2万+

SpringBoot 电商后台管理系统项目介绍

本项目基于SpringBoot框架实现,提供了一套完整的电商后台管理系统解决方案。系统专注于用户管理和权限管理两大核心功能模块,旨在帮助开发者快速构建高效、安全的电商后台系统。通过本项目,您可以直接获得源代码以及相应的数据库脚手架,从而大大简化开发流程。 ## 功能特性 ### 用户管理 - **用户列表**: 展示所有用户的详细信息,包括ID、姓名、电话号码、邮箱、创建时间和用户状态。 -

gitblog_09707的博客 710

电商后台实战:从零搭建SpringBoot项目

最近在做一个电商后台管理系统的项目,用SpringBoot框架从零搭建,过程中积累了一些实战经验,分享给大家做个参考。这个系统主要包含商品管理、订单处理、用户权限和数据统计四大核心模块,采用前后端分离架构,后端提供RESTful API接口。总结下来,SpringBoot开发电商后台要注意模块划分清晰,接口设计规范,性能优化到位。上可以一键部署体验,他们的云环境已经预装了MySQL和Redis,省去了本地配置的麻烦。我测试时发现部署过程特别顺畅,点击按钮就能看到运行效果,适合快速验证项目。

GoldenleafRaven13的博客 493

SpringBoot构建电商秒杀项目实战(一)

源码地址:https://github.com/KiroScarlet/miaoshaproject 慕课网SpringBoot构建电商基础秒杀项目,课程地址https://www.imooc.com/learn/1079 第一章 课程介绍 电商秒杀应用简介 商品列表页获取秒杀商品列表 进入商品详情页获取秒杀商品详情 秒杀开始后进入下单确认页下单并支付成功 第二章 应用SpringBoot...

KiroScarlet的博客 7194

EIP-7587 深度解读:为 RIP 流程保留预编译地址范围(0x0100–0x01FF)

本文围绕 EIP-7587「Reserve Precompile Address Range for RIPs」展开,全面解析以太坊如何通过该提案为 Rollup Improvement Proposal(RIP)流程划出专属的预编译地址区间,从而避免 L2 与 L1 的预编译地址冲突。你将理解预编译地址空间的由来(EIP-1352)、0x0100–0x01FF 这 256 个地址的精确含义、它与

gitblog_09747的博客 720

Spring Boot电商项目59:订单模块八:【后台:订单列表】接口;

说明: (1)本篇博客的主要内容是开发【后台:订单列表】接口; (2)本篇博客没什么难点;只需要注意:【前台:订单列表】接口是查询当前登录用户的订单数据;【后台:订单列表】接口是查询所有用户的订单数据; 目录 一:【后台:订单列表】接口说明; 1.【后台:订单列表】接口,接口文档; 2.【后台:订单列表】接口,在接口上的表现; 二:正式开发; 1.创建OrderAdminController,并在其中创建处理【后台:订单列表】接口的方法:listForAdmin()方法; 2.在Or..

小枯林的博客 2486

mall项目是一套电商系统,包括前台商城系统及后台管理系统,基于SpringBoot+MyBatis实现。

mall 前言 mall项目致力于打造一个完整的电商系统,采用现阶段流行技术实现。 项目文档 文档地址:https://macrozheng.github.io/mall-learning 备用地址:https://macrozheng.gitee.io/mall-learning 项目介绍 mall项目是一套电商系统,包括前台商城系统及后台管理系统,基于SpringBo...

大强博客 1万+
errors11
博客等级 码龄5年 1粉丝 1原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值