餐饮系统店家后端基础功能构建

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
对象存储 OSS,标准 - 本地冗余存储 20GB 3个月
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 餐饮系统店家后端基础功能构建


一、说明


本后台代码实现的功能是针对于商户后台,主要实现图片管理,餐桌管理,菜品管理,订单管理,评分管理,员工信息管理等模块;


并且该项目为了高效快捷,所以采用SpringBoot构建项目,MyBatisPlus做持久化框架,MySQL做数据存储;


二、技术点


SpringBoot

MyBatisPlus

MySQL

OSS文件服务器


三、创建SpringBoot项目


名称:quick-dine-sys-store


image.png

image.png

image.png

image.png

image.png

image.png


四、依赖引入


<properties>
    <java.version>1.8</java.version>
    <mybatis-plus.version>3.4.0</mybatis-plus.version>
    <velocity.version>2.0</velocity.version>
    <swagger.version>2.7.0</swagger.version>
    <aliyun.oss.version>3.1.0</aliyun.oss.version>
    <jodatime.version>2.10.1</jodatime.version>
    <commons-fileupload.version>1.3.1</commons-fileupload.version>
    <commons-io.version>2.6</commons-io.version>
    <commons-lang.version>3.9</commons-lang.version>
    <fastjson.version>1.2.28</fastjson.version>
    <commons-dbutils.version>1.7</commons-dbutils.version>
</properties>
<dependencies>
    <!--web启动器-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!--MySQL驱动-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>
    <!--lombok工具-->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <!--数据访问,mybatisplus-->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>${mybatis-plus.version}</version>
    </dependency>
    <!-- velocity 模板引擎, Mybatis Plus 代码生成器需要 -->
    <dependency>
        <groupId>org.apache.velocity</groupId>
        <artifactId>velocity-engine-core</artifactId>
        <version>${velocity.version}</version>
    </dependency>
    <!--swagger-->
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger2</artifactId>
        <version>${swagger.version}</version>
    </dependency>
    <!--swagger ui-->
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger-ui</artifactId>
        <version>${swagger.version}</version>
    </dependency>
    <!--aliyunOSS-->
    <dependency>
        <groupId>com.aliyun.oss</groupId>
        <artifactId>aliyun-sdk-oss</artifactId>
        <version>${aliyun.oss.version}</version>
    </dependency>
    <!--日期时间工具-->
    <dependency>
        <groupId>joda-time</groupId>
        <artifactId>joda-time</artifactId>
        <version>${jodatime.version}</version>
    </dependency>
    <!--文件上传-->
    <dependency>
        <groupId>commons-fileupload</groupId>
        <artifactId>commons-fileupload</artifactId>
        <version>${commons-fileupload.version}</version>
    </dependency>
    <!--commons-io-->
    <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
        <version>${commons-io.version}</version>
    </dependency>
    <!--commons-lang3-->
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <version>${commons-lang.version}</version>
    </dependency>
    <!--json-->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>${fastjson.version}</version>
    </dependency>
    <!--测试-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
        <exclusions>
            <exclusion>
                <groupId>org.junit.vintage</groupId>
                <artifactId>junit-vintage-engine</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
</dependencies>


五,代码生成器


在test中创建CodeGenerator类


image.png


创建BaseEntity


image.png


@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class BaseEntity implements Serializable {
    private static final long serialVersionUID=1L;
    @ApiModelProperty(value = "ID")
    @TableId(value = "id", type = IdType.ASSIGN_ID)
    private Long id;
    @ApiModelProperty(value = "创建时间")
    @TableField(fill = FieldFill.INSERT)
    private Date createTime;
    @ApiModelProperty(value = "更新时间")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;
}


编写代码生成测试类


/**
 * @Package: cn.liuliang.quickdinesysstore
 * @Author: liuliang
 * @CreateTime: 2020/10/24 - 9:59
 * @Description: 代码生成器
 */
public class CodeGenerator {
    @Test
    public void genCode() {
        String moduleName = "t";
        // 1、创建代码生成器
        AutoGenerator mpg = new AutoGenerator();
        // 2、全局配置
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");
        gc.setOutputDir(projectPath + "/src/main/java");
        gc.setAuthor("j3_liuliang");
        gc.setOpen(false); //生成后是否打开资源管理器
        //        gc.setFileOverride(false); //重新生成时文件是否覆盖
        gc.setServiceName("%sService");    //去掉Service接口的首字母I
        gc.setIdType(IdType.ASSIGN_ID); //主键策略
        gc.setDateType(DateType.ONLY_DATE);//定义生成的实体类中日期类型
        gc.setSwagger2(true);//开启Swagger2模式
        mpg.setGlobalConfig(gc);
        // 3、数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://192.168.159.98:3306/quick_dine_sys?serverTimezone=GMT%2B8");
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("root");
        dsc.setDbType(DbType.MYSQL);
        mpg.setDataSource(dsc);
        // 4、包配置
        PackageConfig pc = new PackageConfig();
        //pc.setModuleName(moduleName); //模块名
        pc.setParent("cn.liuliang.quickdinesysstore");
        pc.setController("controller");
        pc.setEntity("entity");
        pc.setService("service");
        pc.setMapper("mapper");
        mpg.setPackageInfo(pc);
        // 5、策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setNaming(NamingStrategy.underline_to_camel);//数据库表映射到实体的命名策略
        strategy.setTablePrefix(moduleName + "_");//设置表前缀不生成
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);//数据库表字段映射到实体的命名策略
        strategy.setEntityLombokModel(true); // lombok 模型 @Accessors(chain = true) setter链式操作
        strategy.setLogicDeleteFieldName("is_deleted");//逻辑删除字段名
        strategy.setEntityBooleanColumnRemoveIsPrefix(true);//去掉布尔值的is_前缀
        //设置BaseEntity
        strategy.setSuperEntityClass("cn.liuliang.quickdinesysstore.base.BaseEntity");
        // 填写BaseEntity中的公共字段
        strategy.setSuperEntityColumns("id", "create_time", "update_time");
        //自动填充
        TableFill gmtCreate = new TableFill("create_time", FieldFill.INSERT);
        TableFill gmtModified = new TableFill("update_time", FieldFill.INSERT_UPDATE);
        ArrayList<TableFill> tableFills = new ArrayList<>();
        tableFills.add(gmtCreate);
        tableFills.add(gmtModified);
        strategy.setTableFillList(tableFills);
        strategy.setRestControllerStyle(true); //restful api风格控制器
        strategy.setControllerMappingHyphenStyle(true); //url中驼峰转连字符
        mpg.setStrategy(strategy);
        // 6、执行
        mpg.execute();
    }
}


效果


image.png


六、配置Swagger2


前后端分离开发模式中,api文档是最好的沟通方式。


Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。


及时性 (接口变更后,能够及时准确地通知相关前后端开发人员)

规范性 (并且保证接口的规范性,如接口的地址,请求方式,参数及响应格式和错误信息)

一致性 (接口信息一致,不会出现因开发人员拿到的文档版本不一致,而出现分歧)

可测性 (直接在接口文档上进行测试,以方便理解业务)

创建Swagger2配置类:Swagger2Config


image.png


/**
* @Package: cn.liuliang.quickdinesysstore.config
* @Author: liuliang
* @CreateTime: 2020/10/24 - 10:50
* @Description:
*/
@Configuration
@EnableSwagger2
public class Swagger2Config {
    @Bean
    public Docket adminApiConfig(){
        return new Docket(DocumentationType.SWAGGER_2)
            .groupName("adminApi")
            .apiInfo(adminApiInfo())
            .select()
            //只显示admin路径下的页面
            //.paths(Predicates.and(PathSelectors.regex("/admin/.*")))
            .build();
    }
    private ApiInfo adminApiInfo(){
        return new ApiInfoBuilder()
            .title("后台管理系统-API文档")
            .description("本文档描述了后台管理系统微服务接口定义")
            .version("1.0")
            .contact(new Contact("liuliang", "https://blog.csdn.net/qq_40399646", "j3_liuliang@163.com"))
            .build();
    }
}


在controller和entity中加入相关注解即可完成swagger的相关功能,如下:


image.png


访问:http://localhost:项目端口/swagger-ui.html#/

例如:http://localhost:9110/swagger-ui.html#/

效果


image.png


七、统一返回结果


项目中我们会将响应封装成json返回,一般我们会将所有接口的数据格式统一, 使前端(iOS Android, Web)对数据的操作更一致、轻松。


一般情况下,统一返回数据格式没有固定的格式,只要能描述清楚返回的数据状态以及要返回的具体数据就可以。但是一般会包含状态码、返回消息、数据这几部分内容


例如,我们的系统要求返回的基本数据格式如下:


列表:

{
  "success": true,
  "code": 20000,
  "message": "成功",
  "data": {
    "items": [
      {
        "id": "1",
        "name": "刘德华",
        "intro": "毕业于师范大学数学系,热爱教育事业,执教数学思维6年有余"
      }
    ]
  }
}


分页:

{
  "success": true,
  "code": 20000,
  "message": "成功",
  "data": {
    "total": 17,
    "rows": [
      {
        "id": "1",
        "name": "刘德华",
        "intro": "毕业于师范大学数学系,热爱教育事业,执教数学思维6年有余"
      }
    ]
  }
}


没有数据

{
  "success": true,
  "code": 20000,
  "message": "成功",
  "data": {}
}


失败

{
  "success": false,
  "code": 20001,
  "message": "失败",
  "data": {}
}


因此,我们定义统一结果:

{
  "success": 布尔, //响应是否成功
  "code": 数字, //响应码
  "message": 字符串, //返回消息
  "data": HashMap //返回数据,放在键值对中
}


创建如下类

ResultDTO
ResultCodeEnum


位置:


image.png


/**
 * @Package: cn.liuliang.quickdinesysstore.base.result
 * @Author: liuliang
 * @CreateTime: 2020/10/24 - 13:51
 * @Description:
 */
@Data
@ApiModel(value = "全局统一返回结果")
public class ResultDTO {
    @ApiModelProperty(value = "是否成功")
    private Boolean success;
    @ApiModelProperty(value = "返回码")
    private Integer code;
    @ApiModelProperty(value = "返回消息")
    private String message;
    @ApiModelProperty(value = "返回数据")
    private Map<String, Object> data = new HashMap<String, Object>();
    public ResultDTO(){}
    public static ResultDTO success(){
        ResultDTO resultDTO = new ResultDTO();
        resultDTO.setSuccess(ResultCodeEnum.SUCCESS.getSuccess());
        resultDTO.setCode(ResultCodeEnum.SUCCESS.getCode());
        resultDTO.setMessage(ResultCodeEnum.SUCCESS.getMessage());
        return resultDTO;
    }
    public static ResultDTO success(String key, Object value){
        ResultDTO resultDTO = new ResultDTO();
        resultDTO.setSuccess(ResultCodeEnum.SUCCESS.getSuccess());
        resultDTO.setCode(ResultCodeEnum.SUCCESS.getCode());
        resultDTO.setMessage(ResultCodeEnum.SUCCESS.getMessage());
        resultDTO.data.put(key,value);
        return resultDTO;
    }
    public static ResultDTO error(){
        ResultDTO resultDTO = new ResultDTO();
        resultDTO.setSuccess(ResultCodeEnum.UNKNOWN_REASON.getSuccess());
        resultDTO.setCode(ResultCodeEnum.UNKNOWN_REASON.getCode());
        resultDTO.setMessage(ResultCodeEnum.UNKNOWN_REASON.getMessage());
        return resultDTO;
    }
    public static ResultDTO setResult(ResultCodeEnum resultCodeEnum) {
        ResultDTO resultDTO = new ResultDTO();
        resultDTO.setSuccess(resultCodeEnum.getSuccess());
        resultDTO.setCode(resultCodeEnum.getCode());
        resultDTO.setMessage(resultCodeEnum.getMessage());
        return resultDTO;
    }
    public ResultDTO success(Boolean success) {
        this.setSuccess(success);
        return this;
    }
    public ResultDTO message(String message) {
        this.setMessage(message);
        return this;
    }
    public ResultDTO code(Integer code) {
        this.setCode(code);
        return this;
    }
    public ResultDTO data(String key, Object value) {
        this.data.put(key, value);
        return this;
    }
    public ResultDTO data(Map<String, Object> map) {
        this.setData(map);
        return this;
    }
}


/**
 * @Package: cn.liuliang.quickdinesysstore
 * @Author: liuliang
 * @CreateTime: 2020/10/24 - 13:52
 * @Description:
 */
@Getter
@ToString
public enum ResultCodeEnum {
    SUCCESS(true, 20000, "成功"),
    UNKNOWN_REASON(false, 20001, "未知错误"),
    BAD_SQL_GRAMMAR(false, 21001, "sql语法错误"),
    JSON_PARSE_ERROR(false, 21002, "json解析异常"),
    PARAM_ERROR(false, 21003, "参数不正确"),
    FILE_UPLOAD_ERROR(false, 21004, "文件上传错误"),
    FILE_DELETE_ERROR(false, 21005, "文件刪除错误"),
    VIDEO_UPLOAD_ALIYUN_ERROR(false, 22001, "视频上传至阿里云失败"),
    VIDEO_UPLOAD_TOMCAT_ERROR(false, 22002, "视频上传至业务服务器失败"),
    VIDEO_DELETE_ALIYUN_ERROR(false, 22003, "阿里云视频文件删除失败"),
    FETCH_VIDEO_UPLOADAUTH_ERROR(false, 22004, "获取上传地址和凭证失败"),
    REFRESH_VIDEO_UPLOADAUTH_ERROR(false, 22005, "刷新上传地址和凭证失败"),
    URL_ENCODE_ERROR(false, 23001, "URL编码失败"),
    ILLEGAL_CALLBACK_REQUEST_ERROR(false, 23002, "非法回调请求"),
    FETCH_ACCESSTOKEN_FAILD(false, 23003, "获取accessToken失败"),
    FETCH_USERINFO_ERROR(false, 23004, "获取用户信息失败"),
    LOGIN_ERROR(false, 23005, "登录失败"),
    PAY_RUN(false, 25000, "支付中"),
    PAY_UNIFIEDORDER_ERROR(false, 25001, "统一下单错误"),
    PAY_ORDERQUERY_ERROR(false, 25002, "查询支付结果错误"),
    GATEWAY_ERROR(false, 26000, "服务不能访问"),
    LOGIN_PHONE_ERROR(false, 28009, "手机号码不正确"),
    LOGIN_MOBILE_ERROR(false, 28001, "账号不正确"),
    LOGIN_PASSWORD_ERROR(false, 28008, "密码不正确"),
    LOGIN_DISABLED_ERROR(false, 28002, "该用户已被禁用"),
    REGISTER_MOBLE_ERROR(false, 28003, "手机号已被注册"),
    LOGIN_AUTH(false, 28004, "需要登录");
    private Boolean success;
    private Integer code;
    private String message;
    ResultCodeEnum(Boolean success, Integer code, String message) {
        this.success = success;
        this.code = code;
        this.message = message;
    }
}


修改菜品管理类:DishesController


@Api(value = "菜品管理", tags = "菜品管理")
@RestController
@RequestMapping("/dishes")
public class DishesController {
    @Autowired
    private DishesService dishesService;
    @ApiOperation(value = "获取所有菜品信息", notes = "获取所有菜品信息")
    @GetMapping("/getAll")
    public ResultDTO getAll() {
        return ResultDTO.success("items", dishesService.list());
    }
}


效果:


image.png


八、分页查询


新建:MybatisPlusConfig配置类


image.png


/**
 * @Package: cn.liuliang.quickdinesysstore.config
 * @Author: liuliang
 * @CreateTime: 2020/10/24 - 10:29
 * @Description:
 */
@EnableTransactionManagement
@Configuration
@MapperScan("cn.liuliang.quickdinesysstore.mapper")
public class MybatisPlusConfig {
    /**
     * 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}


控制层代码使用分页插件


@ApiOperation(value = "获取所有菜品信息", notes = "获取所有菜品信息")
@GetMapping("/getAll")
public ResultDTO getAll(@ApiParam("当前页码") @RequestParam(value = "pageNum", required = false, defaultValue = "1") Integer pageNum,
                        @ApiParam("每页显示条数") @RequestParam(value = "pageSize", required = false, defaultValue = "10") Integer pageSize) {
    // 分页设置
    Page<Dishes> pageParam = new Page<>(pageNum, pageSize);
    // 业务类调用分页查询方法,分页查询
    IPage<Dishes> page = dishesService.page(pageParam);
    // 获取结果
    List<Dishes> records = page.getRecords();
    // 获取总条数
    long total = page.getTotal();
    return ResultDTO.success().data("total", total).data("rows", records);
}


效果:


{
  "success": true,
  "code": 20000,
  "message": "成功",
  "data": {
    "total": 4,
    "rows": [
      {
        "id": 1,
        "createTime": "2020-10-24 10:39:00",
        "updateTime": "2020-10-24 10:39:02",
        "dishesName": "麻婆豆腐",
        "dishesTypeId": 1,
        "briefIntroduction": "好处不上火,还便宜",
        "imageUrl": null,
        "price": 18
      },
      {
        "id": 2,
        "createTime": "2020-10-24 14:32:03",
        "updateTime": "2020-10-24 14:32:04",
        "dishesName": "辣椒炒肉",
        "dishesTypeId": 1,
        "briefIntroduction": null,
        "imageUrl": null,
        "price": 26
      }
    ]
  }
}


九、自动填充


创建类:MyMetaObjectHandler


image.png


@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
    /**
     * 插入数据时,填充字段
     * @param metaObject
     */
    @Override
    public void insertFill(MetaObject metaObject) {
        //可以查看官网 自动填充那一快
        //第一种:this.setFieldValByName("createTime", new Date(), metaObject);
        //第二种: Date.class 要与实体类中字段的类型一样,否者就是不填充  strict:严格的
        this.strictInsertFill(metaObject, "createTime", Date.class, new Date()); // 起始版本 3.3.0(推荐使用)
        //this.setFieldValByName("updateTime", new Date(), metaObject);
        this.strictInsertFill(metaObject, "updateTime", Date.class, new Date()); // 起始版本 3.3.0(推荐使用)
    }
    /**
     * 修改数据时,填充字段
     * @param metaObject
     */
    @Override
    public void updateFill(MetaObject metaObject) {
        //this.setFieldValByName("updateTime", new Date(), metaObject);
        this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date()); // 起始版本 3.3.0(推荐)
    }
}


十、统一异常处理


我们想让异常结果也显示为统一的返回结果对象,并且统一处理系统的异常信息,那么需要统一异常处理

创建统一异常处理器:GlobalExceptionHandler

自定义异常类:QuickException


image.png


/**
 * @Package: cn.liuliang.quickdinesysstore.handler
 * @Author: liuliang
 * @CreateTime: 2020/10/24 - 15:24
 * @Description:
 */
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public ResultDTO error(Exception e) {
        log.error("error", e);
        return ResultDTO.error();
    }
    @ExceptionHandler(BadSqlGrammarException.class)
    @ResponseBody
    public ResultDTO error(BadSqlGrammarException e) {
        log.error("error", e);
        return ResultDTO.setResult(ResultCodeEnum.BAD_SQL_GRAMMAR);
    }
    @ExceptionHandler(HttpMessageNotReadableException.class)
    @ResponseBody
    public ResultDTO error(HttpMessageNotReadableException e) {
        log.error("error", e);
        return ResultDTO.setResult(ResultCodeEnum.JSON_PARSE_ERROR);
    }
    @ExceptionHandler(QuickException.class)
    @ResponseBody
    public ResultDTO error(QuickException e) {
        log.error("error", e);
        return ResultDTO.error().message(e.getMessage()).code(e.getCode());
    }
}


/**
 * @Package: cn.liuliang.quickdinesysstore.exception
 * @Author: liuliang
 * @CreateTime: 2020/10/24 - 15:27
 * @Description:
 */
@Data
public class QuickException extends RuntimeException {
    private Integer code;
    public QuickException(String message, Integer code) {
        super(message);
        this.code = code;
    }
    public QuickException(ResultCodeEnum resultCodeEnum) {
        super(resultCodeEnum.getMessage());
        this.code = resultCodeEnum.getCode();
    }
    @Override
    public String toString() {
        return "GuLiException{" +
                "code=" + code +
                ",message=" + this.getMessage() +
                '}';
    }
}


案例:


@Override
public ResultDTO add(DishesVO dishesVO) {
    Dishes dishes = new Dishes();
    BeanUtils.copyProperties(dishesVO, dishes);
    boolean save = this.save(dishes);
    if (save) {
        return ResultDTO.success();
    } else {
        // 抛出自定义异常
        throw new QuickException("插入失败", 400);
    }
}


效果:


image.png


十一、统一日志处理


resources 中创建 logback-spring.xml (默认日志的名字,必须是这个名字)


<?xml version="1.0" encoding="UTF-8"?>
<configuration  scan="true" scanPeriod="10 seconds">
    <contextName>logback</contextName>
    <property name="log.path" value="E:/java_work_file/quick-dine-sys-store/log" />
    <!--控制台日志格式:彩色日志-->
    <!-- magenta:洋红 -->
    <!-- boldMagenta:粗红-->
    <!-- cyan:青色 -->
    <!-- white:白色 -->
    <!-- magenta:洋红 -->
    <property name="CONSOLE_LOG_PATTERN"
              value="%yellow(%date{yyyy-MM-dd HH:mm:ss}) |%highlight(%-5level) |%blue(%thread) |%blue(%file:%line) |%green(%logger) |%cyan(%msg%n)"/>
    <!--文件日志格式-->
    <property name="FILE_LOG_PATTERN"
              value="%date{yyyy-MM-dd HH:mm:ss} |%-5level |%thread |%file:%line |%logger |%msg%n" />
    <!--编码-->
    <property name="ENCODING"
              value="UTF-8" />
    <!--输出到控制台-->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <!--日志级别-->
            <level>DEBUG</level>
        </filter>
        <encoder>
            <!--日志格式-->
            <Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
            <!--日志字符集-->
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>
    <!--输出到文件-->
    <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!--日志过滤器:此日志文件只记录INFO级别的-->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>INFO</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${log.path}/log_info.log</file>
        <encoder>
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 每天日志归档路径以及格式 -->
            <fileNamePattern>${log.path}/info/log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文件保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
    </appender>
    <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 日志过滤器:此日志文件只记录WARN级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>WARN</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${log.path}/log_warn.log</file>
        <encoder>
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset> <!-- 此处设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.path}/warn/log-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文件保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
    </appender>
    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 日志过滤器:此日志文件只记录ERROR级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${log.path}/log_error.log</file>
        <encoder>
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset> <!-- 此处设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.path}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文件保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
    </appender>
    <!--开发环境-->
    <springProfile name="dev">
        <!--可以灵活设置此处,从而控制日志的输出-->
        <root level="DEBUG">
            <appender-ref ref="CONSOLE" />
            <appender-ref ref="INFO_FILE" />
            <appender-ref ref="WARN_FILE" />
            <appender-ref ref="ERROR_FILE" />
        </root>
    </springProfile>
    <!--生产环境-->
    <springProfile name="pro">
        <root level="ERROR">
            <appender-ref ref="ERROR_FILE" />
        </root>
    </springProfile>
</configuration>


// 输出错误堆栈信息,可以在项目的全局异常处理中使用
log.error("error", e);


到此项目的基本边角就已经是搭建完成了,如果后期有变动的话,会第一时间来补充的


结束语


  • 下期开始实现快捷餐饮店家后台项目的功能模块
  • 由于博主才疏学浅,难免会有纰漏,假如你发现了错误或偏见的地方,还望留言给我指出来,我会对其加以修正。
  • 如果你觉得文章还不错,你的转发、分享、点赞、留言就是对我最大的鼓励。
  • 感谢您的阅读,十分欢迎并感谢您的关注。


目录
相关文章
|
2月前
|
存储 前端开发 安全
实现“永久登录”:针对蜻蜓Q系统的用户体验优化方案(前端uni-app+后端Laravel详解)-优雅草卓伊凡
实现“永久登录”:针对蜻蜓Q系统的用户体验优化方案(前端uni-app+后端Laravel详解)-优雅草卓伊凡
188 5
|
6月前
|
JavaScript 前端开发 Java
制造业ERP源码,工厂ERP管理系统,前端框架:Vue,后端框架:SpringBoot
这是一套基于SpringBoot+Vue技术栈开发的ERP企业管理系统,采用Java语言与vscode工具。系统涵盖采购/销售、出入库、生产、品质管理等功能,整合客户与供应商数据,支持在线协同和业务全流程管控。同时提供主数据管理、权限控制、工作流审批、报表自定义及打印、在线报表开发和自定义表单功能,助力企业实现高效自动化管理,并通过UniAPP实现移动端支持,满足多场景应用需求。
620 1
|
4月前
|
小程序 安全 关系型数据库
专业打造一款圈子源码软件系统 / 后端 PHP 搭建部署一样实现利益化
本教程详解基于PHP后端与Uni-app的小程序开发全流程,涵盖技术选型、环境搭建、源码导入、接口对接及功能实现。采用Laravel/Symfony框架,结合MySQL/PostgreSQL数据库,使用WebSocket实现实时通信,并集成IM SDK实现音视频聊天。前端使用Uni-app开发,支持跨平台运行。教程包含完整部署流程与安全优化方案,助力快速搭建高性能、安全稳定的小程序系统。
363 5
|
8月前
|
JSON 自然语言处理 前端开发
【01】对APP进行语言包功能开发-APP自动识别地区ip后分配对应的语言功能复杂吗?-成熟app项目语言包功能定制开发-前端以uniapp-基于vue.js后端以laravel基于php为例项目实战-优雅草卓伊凡
【01】对APP进行语言包功能开发-APP自动识别地区ip后分配对应的语言功能复杂吗?-成熟app项目语言包功能定制开发-前端以uniapp-基于vue.js后端以laravel基于php为例项目实战-优雅草卓伊凡
453 72
【01】对APP进行语言包功能开发-APP自动识别地区ip后分配对应的语言功能复杂吗?-成熟app项目语言包功能定制开发-前端以uniapp-基于vue.js后端以laravel基于php为例项目实战-优雅草卓伊凡
|
6月前
|
存储 消息中间件 前端开发
PHP后端与uni-app前端协同的校园圈子系统:校园社交场景的跨端开发实践
校园圈子系统校园论坛小程序采用uni-app前端框架,支持多端运行,结合PHP后端(如ThinkPHP/Laravel),实现用户认证、社交关系管理、动态发布与实时聊天功能。前端通过组件化开发和uni.request与后端交互,后端提供RESTful API处理业务逻辑并存储数据于MySQL。同时引入Redis缓存热点数据,RabbitMQ处理异步任务,优化系统性能。核心功能包括JWT身份验证、好友系统、WebSocket实时聊天及活动管理,确保高效稳定的用户体验。
413 4
PHP后端与uni-app前端协同的校园圈子系统:校园社交场景的跨端开发实践
|
5月前
|
SQL 中间件 Go
开箱即用的GO后台管理系统 Kratos Admin - 后端项目结构说明
Kratos Admin 是一个开箱即用的 Go 语言后台管理系统,采用 Kratos 框架构建,提供清晰的项目结构与模块化设计。目录包含 API 定义、服务代码、配置文件、数据库初始化脚本及部署工具,支持 Docker 部署与自动化构建,便于快速开发和维护企业级应用。
225 1
|
5月前
|
JSON Cloud Native Go
开箱即用的GO后台管理系统 Kratos Admin - 后端权限控制
后端的权限控制主要分为两种: API权限控制; 数据权限控制。 在本文,我们不讨论数据权限的控制,主要讲API的权限控制。
390 1
|
5月前
|
自然语言处理 JavaScript 前端开发
一夜获千星!已获 1.7k+,Art Design Pro:Vue3 + Vite + TypeScript 打造的高颜值管理系统模板,这个让后端小哥直呼救命的后台系统
Art Design Pro 是一款基于 Vue 3、Vite 和 TypeScript 的高颜值后台管理系统模板,已获 1.7k+ 星标。项目专注于用户体验与视觉设计,支持主题切换、多语言、权限管理及图表展示等功能,内置常用业务组件,便于快速搭建现代化管理界面。其技术栈先进,开发体验流畅,适配多设备,满足企业级应用需求。项目地址:[GitHub](https://github.com/Daymychen/art-design-pro)。
926 11
|
4月前
|
消息中间件 缓存 负载均衡
构建高效可扩展的后端架构:从设计到实现
本文探讨了如何构建高效、可扩展的后端架构,涵盖需求分析、系统设计、实现与优化全过程。内容包括微服务、数据库设计、缓存与消息队列等关键技术,并涉及API设计、自动化测试、CI/CD及性能优化策略,助力打造高性能、易维护的后端系统。
|
6月前
|
开发框架 Java 关系型数据库
在Linux系统中安装JDK、Tomcat、MySQL以及部署J2EE后端接口
校验时,浏览器输入:http://[your_server_IP]:8080/myapp。如果你看到你的应用的欢迎页面,恭喜你,一切都已就绪。
504 17

热门文章

最新文章