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

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
对象存储 OSS,20GB 3个月
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
简介: 餐饮系统店家后端基础功能构建


一、说明


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


并且该项目为了高效快捷,所以采用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);


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


结束语


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


目录
相关文章
|
8天前
|
缓存 API 持续交付
构建高效后端服务的实践之路
【10月更文挑战第34天】在数字化时代的浪潮中,后端服务是支撑整个互联网的脊梁。本文将深入探讨如何构建一个高效的后端服务,涵盖从选择合适的编程语言和框架,到设计高性能的数据库交互、实现缓存机制、优化API设计,以及确保服务的高可用性和可扩展性。我们将通过实际代码示例,展示如何在面对复杂业务逻辑时,依然能够保持后端服务的高效与稳定。无论你是后端开发的新手,还是希望提升现有服务性能的资深开发者,这篇文章都将为你提供宝贵的实践经验和启示。
|
27天前
|
SQL 负载均衡 关系型数据库
构建高效的后端服务:从设计到部署
【10月更文挑战第16天】 在当今的数字化时代,后端服务的效率和可靠性对于任何成功的在线业务至关重要。本文将探讨如何设计和部署一个高效的后端服务,包括选择合适的技术栈、优化数据库性能、实现负载均衡以及确保安全性。我们将通过具体的案例分析,展示这些策略如何在实际中应用,并提供一些实用的技巧和最佳实践。
105 50
|
7天前
|
存储 SQL API
探索后端开发:构建高效API与数据库交互
【10月更文挑战第36天】在数字化时代,后端开发是连接用户界面和数据存储的桥梁。本文深入探讨如何设计高效的API以及如何实现API与数据库之间的无缝交互,确保数据的一致性和高性能。我们将从基础概念出发,逐步深入到实战技巧,为读者提供一个清晰的后端开发路线图。
|
22天前
|
Kubernetes 负载均衡 Docker
构建高效后端服务:微服务架构的探索与实践
【10月更文挑战第20天】 在数字化时代,后端服务的构建对于任何在线业务的成功至关重要。本文将深入探讨微服务架构的概念、优势以及如何在实际项目中有效实施。我们将从微服务的基本理念出发,逐步解析其在提高系统可维护性、扩展性和敏捷性方面的作用。通过实际案例分析,揭示微服务架构在不同场景下的应用策略和最佳实践。无论你是后端开发新手还是经验丰富的工程师,本文都将为你提供宝贵的见解和实用的指导。
|
15天前
|
JavaScript 中间件 关系型数据库
构建高效的后端服务:Node.js 与 Express 的实践指南
在后端开发领域,Node.js 与 Express 的组合因其轻量级和高效性而广受欢迎。本文将深入探讨如何利用这一组合构建高性能的后端服务。我们将从 Node.js 的事件驱动和非阻塞 I/O 模型出发,解释其如何优化网络请求处理。接着,通过 Express 框架的简洁 API,展示如何快速搭建 RESTful API。文章还将涉及中间件的使用,以及如何结合 MySQL 数据库进行数据操作。最后,我们将讨论性能优化技巧,包括异步编程模式和缓存策略,以确保服务的稳定性和扩展性。
|
13天前
|
存储 监控 NoSQL
构建高效后端服务:从理论到实践
【10月更文挑战第30天】在数字化时代,后端服务是支撑起整个互联网的基石。一个高效、稳定且可扩展的后端系统对于任何在线业务都是至关重要的。本文将带你了解如何从零开始构建一个高效的后端服务,涵盖了设计思路、关键技术选型、开发流程以及性能优化等方面。我们将通过实际的代码示例和案例分析,深入探讨如何实现一个既快速又可靠的后端系统。无论你是后端开发的新手还是有经验的开发者,这篇文章都将为你提供宝贵的参考和启示。
31 3
|
16天前
|
前端开发 关系型数据库 API
深入浅出后端开发——从零到一构建RESTful API
本文旨在为初学者提供一个关于后端开发的全面指南,特别是如何从零开始构建一个RESTful API。我们将探讨后端开发的基本概念、所需技术栈、以及通过实际案例展示如何设计和实现一个简单的RESTful API。无论你是完全的新手还是有一定编程基础的开发者,这篇文章都将为你提供实用的知识和技巧,帮助你在后端开发的道路上迈出坚实的一步。
|
21天前
|
监控 API 持续交付
构建高效后端服务:微服务架构的深度探索
【10月更文挑战第20天】 在数字化时代,后端服务的构建对于支撑复杂的业务逻辑和海量数据处理至关重要。本文深入探讨了微服务架构的核心理念、实施策略以及面临的挑战,旨在为开发者提供一套构建高效、可扩展后端服务的方法论。通过案例分析,揭示微服务如何帮助企业应对快速变化的业务需求,同时保持系统的稳定性和灵活性。
46 9
|
19天前
|
存储 SQL 缓存
构建高效后端服务:从理论到实践
在当今的软件开发领域,后端服务扮演着至关重要的角色。它不仅支撑着应用程序的核心功能,还影响着系统的性能、可扩展性和用户体验。本文将深入探讨如何构建一个高效的后端服务,涵盖从需求分析到架构设计,再到技术选型和性能优化的全过程。我们将通过实际案例,展示如何在保证数据一致性和安全性的前提下,实现高并发处理和快速响应。无论你是后端开发的新手还是有经验的工程师,这篇文章都将为你提供宝贵的见解和实用的建议。
|
18天前
|
缓存 负载均衡 安全
后端开发的艺术:构建高效、可扩展的API
在现代软件开发中,后端开发扮演着至关重要的角色。它不仅负责处理数据存储、业务逻辑和安全性,还需要提供高效、可扩展的API供前端和其他服务使用。本文将深入探讨后端开发的关键概念和技术,帮助读者了解如何构建高效、可扩展的API,并提供一些实用的建议和最佳实践。

热门文章

最新文章