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

本文涉及的产品
对象存储 OSS,20GB 3个月
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
对象存储 OSS,恶意文件检测 1000次 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);


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


结束语


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


目录
相关文章
|
21天前
|
前端开发 JavaScript 关系型数据库
从前端到后端:构建现代化Web应用的技术探索
在当今互联网时代,Web应用的开发已成为了各行各业不可或缺的一部分。从前端到后端,这篇文章将带你深入探索如何构建现代化的Web应用。我们将介绍多种技术,包括前端开发、后端开发以及各种编程语言(如Java、Python、C、PHP、Go)和数据库,帮助你了解如何利用这些技术构建出高效、安全和可扩展的Web应用。
|
22天前
|
API 数据库 开发者
构建高效可靠的微服务架构:后端开发的新范式
【4月更文挑战第8天】 随着现代软件开发的复杂性日益增加,传统的单体应用架构面临着可扩展性、维护性和敏捷性的挑战。为了解决这些问题,微服务架构应运而生,并迅速成为后端开发领域的一股清流。本文将深入探讨微服务架构的设计原则、实施策略及其带来的优势与挑战,为后端开发者提供一种全新视角,以实现更加灵活、高效和稳定的系统构建。
23 0
|
29天前
|
缓存 监控 持续交付
构建高效微服务架构:后端开发者的七大秘诀
在本文中,我们将深入探讨构建和维护高效微服务架构的关键策略。不同于常规的技术细节介绍,我们将重点放在实践技巧和方法论上,帮助后端开发者提升系统设计能力,确保微服务架构的稳定性、扩展性和安全性。从服务划分到数据一致性,再到服务监控与调优,文中将提供一系列实用的建议和最佳实践,旨在指导读者如何在复杂多变的业务环境中构建出健壮且高效的微服务体系。
|
10天前
|
消息中间件 监控 持续交付
构建高效微服务架构:后端开发的进阶之路
【4月更文挑战第20天】 随着现代软件开发的复杂性日益增加,传统的单体应用已难以满足快速迭代和灵活部署的需求。微服务架构作为一种新兴的分布式系统设计方式,以其独立部署、易于扩展和维护的特点,成为解决这一问题的关键。本文将深入探讨微服务的核心概念、设计原则以及在后端开发实践中如何构建一个高效的微服务架构。我们将从服务划分、通信机制、数据一致性、服务发现与注册等方面入手,提供一系列实用的策略和建议,帮助开发者优化后端系统的性能和可维护性。
|
5天前
|
消息中间件 负载均衡 持续交付
构建高效微服务架构:后端开发者的终极指南
【4月更文挑战第25天】在当今软件工程领域,微服务架构已经成为实现可扩展、灵活且容错的系统的首选模式。本文将探讨如何从零开始构建一个高效的微服务系统,涵盖关键组件的选择、通信机制、数据管理以及持续集成和部署策略。通过深入分析与案例研究,我们旨在为后端开发者提供一个全面的微服务实践指南,帮助他们在构建现代化应用时做出明智的架构决策。
|
22天前
|
消息中间件 Java 微服务
构建高性能微服务架构:Java后端实践
【4月更文挑战第8天】 在当今互联网应用的快速迭代与高并发挑战下,微服务架构以其灵活性和扩展性成为众多企业技术选型的宠儿。本文将深入探讨在Java后端开发中,如何构建一个高性能的微服务系统,涵盖从基础架构设计、关键技术选型到性能优化策略的全方位分析。我们将透过实际案例,剖析微服务实践中的最佳模式与常见陷阱,为后端开发人员提供一份实操指南。
|
1天前
|
安全 Java 开发者
构建高效微服务架构:后端开发的新范式Java中的多线程并发编程实践
【4月更文挑战第29天】在数字化转型的浪潮中,微服务架构已成为软件开发的一大趋势。它通过解耦复杂系统、提升可伸缩性和促进敏捷开发来满足现代企业不断变化的业务需求。本文将深入探讨微服务的核心概念、设计原则以及如何利用最新的后端技术栈构建和部署高效的微服务架构。我们将分析微服务带来的挑战,包括服务治理、数据一致性和网络延迟问题,并讨论相应的解决方案。通过实际案例分析和最佳实践的分享,旨在为后端开发者提供一套实施微服务的全面指导。 【4月更文挑战第29天】在现代软件开发中,多线程技术是提高程序性能和响应能力的重要手段。本文通过介绍Java语言的多线程机制,探讨了如何有效地实现线程同步和通信,以及如
|
5天前
|
前端开发 JavaScript Java
前端与后端:构建现代Web应用的双翼
前端与后端:构建现代Web应用的双翼
|
6天前
|
持续交付 API 开发者
构建高效微服务架构:后端开发的新范式
【4月更文挑战第24天】 随着现代软件系统的复杂性日益增加,传统的单体应用已难以满足快速迭代与灵活扩展的需求。微服务架构作为一种新兴的软件开发模式,以其服务的细粒度、独立部署和弹性伸缩等优势,正在逐渐成为后端开发的重要趋势。本文将深入探讨微服务架构的设计原则、关键技术以及在实际业务中的应用实践,旨在为后端开发者提供构建和维护高效微服务架构的参考指南。
|
7天前
|
Kubernetes API 持续交付
构建高效微服务架构:后端开发的现代实践
【4月更文挑战第23天】 在当今快速迭代的软件开发领域,微服务架构已成为实现可扩展、灵活且独立部署服务的标准解决方案。本文将深入探讨构建高效微服务的关键要素,包括服务划分原则、容器化技术、API网关设计以及持续集成和持续部署(CI/CD)的实践。通过分析这些要素,我们将展示如何在保证系统稳定性的同时,提高开发效率和服务可靠性。