SpringBoot 企业微信点餐系统实战二:日志配置、商品类目开发

2022-04-06 12:54:13 浏览数 (1)

这是【SpringBoot企业微信点餐系统实战】系列第二篇

源码地址:https://github.com/cachecats/sell

一、依赖引入和数据库配置

编辑 pom.xml 引入 mysqljpalombok 依赖

代码语言:javascript复制
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

&lt;groupId&gt;com.solo&lt;/groupId&gt;
&lt;artifactId&gt;sell&lt;/artifactId&gt;
&lt;version&gt;0.0.1-SNAPSHOT&lt;/version&gt;
&lt;packaging&gt;jar&lt;/packaging&gt;

&lt;name&gt;sell&lt;/name&gt;
&lt;description&gt;Demo project <span class="hljs-keyword">for</span> Spring Boot&lt;/description&gt;

&lt;parent&gt;
    &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
    &lt;artifactId&gt;spring-boot-starter-parent&lt;/artifactId&gt;
    &lt;version&gt;2.0.4.RELEASE&lt;/version&gt;
    &lt;relativePath/&gt; &lt;!-- lookup parent from repository --&gt;
&lt;/parent&gt;

&lt;properties&gt;
    &lt;project.build.sourceEncoding&gt;UTF-8&lt;/project.build.sourceEncoding&gt;
    &lt;project.reporting.outputEncoding&gt;UTF-8&lt;/project.reporting.outputEncoding&gt;
    &lt;java.version&gt;1.8&lt;/java.version&gt;
&lt;/properties&gt;

&lt;dependencies&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
        &lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt;
    &lt;/dependency&gt;

    &lt;dependency&gt;
        &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
        &lt;artifactId&gt;spring-boot-starter-test&lt;/artifactId&gt;
        &lt;scope&gt;<span class="hljs-built_in">test</span>&lt;/scope&gt;
    &lt;/dependency&gt;

    &lt;dependency&gt;
        &lt;groupId&gt;mysql&lt;/groupId&gt;
        &lt;artifactId&gt;mysql-connector-java&lt;/artifactId&gt;
    &lt;/dependency&gt;

    &lt;dependency&gt;
        &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
        &lt;artifactId&gt;spring-boot-starter-data-jpa&lt;/artifactId&gt;
    &lt;/dependency&gt;

    &lt;dependency&gt;
        &lt;groupId&gt;org.projectlombok&lt;/groupId&gt;
        &lt;artifactId&gt;lombok&lt;/artifactId&gt;
    &lt;/dependency&gt;
&lt;/dependencies&gt;

&lt;build&gt;
    &lt;plugins&gt;
        &lt;plugin&gt;
            &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
            &lt;artifactId&gt;spring-boot-maven-plugin&lt;/artifactId&gt;
        &lt;/plugin&gt;
    &lt;/plugins&gt;
&lt;/build&gt;

</project>

application.properties 改名为 application.yml ,不改也行但 yml 文件写起来更爽。配置数据库连接和 jpa

代码语言:javascript复制
spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    username: root
    password: root
    url: jdbc:mysql://127.0.0.1/sell?characterEncoding=utf-8&useSSL=false
  jpa:
    show-sql: true

二、项目日志配置

最终选择了 LogBack 作为日志工具,配置如下:

项目目录/src/main/resources 目录下新建 logback 配置文件 logback-spring.xml

代码语言:javascript复制
<?xml version="1.0" encoding="UTF-8" ?>

<configuration>
&lt;appender name=<span class="hljs-string">"consoleLog"</span> class=<span class="hljs-string">"ch.qos.logback.core.ConsoleAppender"</span>&gt;
    &lt;layout class=<span class="hljs-string">"ch.qos.logback.classic.PatternLayout"</span>&gt;
        &lt;pattern&gt;
            %d - %msg%n
        &lt;/pattern&gt;
    &lt;/layout&gt;
&lt;/appender&gt;

&lt;appender name=<span class="hljs-string">"fileInfoLog"</span> class=<span class="hljs-string">"ch.qos.logback.core.rolling.RollingFileAppender"</span>&gt;
    &lt;filter class=<span class="hljs-string">"ch.qos.logback.classic.filter.LevelFilter"</span>&gt;
        &lt;level&gt;ERROR&lt;/level&gt;
        &lt;onMatch&gt;DENY&lt;/onMatch&gt;
        &lt;onMismatch&gt;ACCEPT&lt;/onMismatch&gt;
    &lt;/filter&gt;
    &lt;encoder&gt;
        &lt;pattern&gt;
            %msg%n
        &lt;/pattern&gt;
    &lt;/encoder&gt;
    &lt;!--滚动策略--&gt;
    &lt;rollingPolicy class=<span class="hljs-string">"ch.qos.logback.core.rolling.TimeBasedRollingPolicy"</span>&gt;
        &lt;!--路径--&gt;
        &lt;fileNamePattern&gt;/Users/solo/Documents/project/springboot/<span class="hljs-built_in">log</span>/info.%d.log&lt;/fileNamePattern&gt;
    &lt;/rollingPolicy&gt;
&lt;/appender&gt;


&lt;appender name=<span class="hljs-string">"fileErrorLog"</span> class=<span class="hljs-string">"ch.qos.logback.core.rolling.RollingFileAppender"</span>&gt;
    &lt;filter class=<span class="hljs-string">"ch.qos.logback.classic.filter.ThresholdFilter"</span>&gt;
        &lt;level&gt;ERROR&lt;/level&gt;
    &lt;/filter&gt;
    &lt;encoder&gt;
        &lt;pattern&gt;
            %msg%n
        &lt;/pattern&gt;
    &lt;/encoder&gt;
    &lt;!--滚动策略--&gt;
    &lt;rollingPolicy class=<span class="hljs-string">"ch.qos.logback.core.rolling.TimeBasedRollingPolicy"</span>&gt;
        &lt;!--路径--&gt;
        &lt;fileNamePattern&gt;/Users/solo/Documents/project/springboot/<span class="hljs-built_in">log</span>/error.%d.log&lt;/fileNamePattern&gt;
    &lt;/rollingPolicy&gt;
&lt;/appender&gt;

&lt;root level=<span class="hljs-string">"info"</span>&gt;
    &lt;appender-ref ref=<span class="hljs-string">"consoleLog"</span> /&gt;
    &lt;appender-ref ref=<span class="hljs-string">"fileInfoLog"</span> /&gt;
    &lt;appender-ref ref=<span class="hljs-string">"fileErrorLog"</span> /&gt;
&lt;/root&gt;

</configuration>

这里配置了日志格式、每天生成日志文件到指定目录、error 和其他级别日志分开、滚动策略等,就不一一介绍了,把这个文件粘到项目中就可以。

三、商品类目dao、service层开发

上篇文章介绍了数据库的设计,今天就来开发具体业务吧。 开发顺序基本是每个表先写 dto类,再写 dao 层,再写 service 层,每步开发完都进行单元测试。

3.1 类目 dto

这个没什么难度,照着数据库表每个字段写下来就好,采用驼峰式命名规则。 为方便比较,先给出上篇的商品类目 product_category sql创建语句

代码语言:javascript复制
create table `product_category`(
    `category_id` int not null auto_increment,
    `category_name` varchar(64) not null comment '类目名字',
    `category_type` int not null comment '类目编号',
    `create_time` timestamp not null default current_timestamp comment '创建时间',
    `update_time` timestamp not null default current_timestamp on update current_timestamp comment '修改时间',
    primary key (`category_id`),
    unique key `uqe_category_type` (`category_type`)
) comment '类目表';

新建 dto 包,在该包下新建 javaProductCategory

代码语言:javascript复制
package com.solo.sell.dto;

import lombok.Data;
import org.hibernate.annotations.DynamicUpdate;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
/**

商品分类

 */
@Entity
@DynamicUpdate
@Data
public class ProductCategory {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer categoryId;

/** 种类名称 */
private String categoryName;

/** 种类类型 */
private Integer categoryType;

public <span class="hljs-function"><span class="hljs-title">ProductCategory</span></span>() {
}

public ProductCategory(String categoryName, Integer categoryType) {
    this.categoryName = categoryName;
    this.categoryType = categoryType;
}

}

说一下类名上面的三个注解: @Entity:表示这是一个entity实体类 @DynamicUpdate:因为数据库中updateTime字段设置了自动更新,如果不加这个注解,自动更新将不会生效 @Data:lombok 的辅助方法,可以自动生成 Get、Set、toString方法,官方文档介绍:

@Data All together now: A shortcut for @ToString, @EqualsAndHashCode, @Getter on all fields, and @Setter on all non-final fields, and @RequiredArgsConstructor!

注意:如果重写了构造方法,一定要加一个无参构造,否则后面会报错。

3.2 商品类目 repository

新建 repository 包,用来存放数据库操作的仓库。 数据库操作用 JPA ,新建接口ProductCategoryRepository 继承自 JpaRepository.

代码语言:javascript复制
public interface ProductCategoryRepository extends JpaRepository<ProductCategory, Integer>{

/**
 * 传入类型列表,查询包含列表中类型的所有数据
 */
List&lt;ProductCategory&gt; findByCategoryTypeIn(List&lt;Integer&gt; types);

}

JpaRepository<ProductCategory, Integer>里面有两个参数,第一个是数据表对应的实体类名,第二个是主键类型。 这里添加一个方法 findByCategoryTypeIn(List<Integer> types),传入商品类目的类型列表,返回包含这些类目的所有数据。

3.3 商品类目 service

新建 service 包,创建接口 ProductCategoryService

代码语言:javascript复制
package com.solo.sell.service;

import com.solo.sell.dto.ProductCategory;
import java.util.List;
public interface ProductCategoryService {
ProductCategory findOne(Integer id);

List&lt;ProductCategory&gt; findAll();

ProductCategory save(ProductCategory productCategory);

List&lt;ProductCategory&gt; findByCategoryTypeIn(List&lt;Integer&gt; types);

}

service 包下新建 impl 存放 service 的实现类,并创建 ProductCategoryService 的实现类 ProductCategoryServiceImpl

代码语言:javascript复制
package com.solo.sell.service.impl;

import com.solo.sell.dto.ProductCategory;
import com.solo.sell.repository.ProductCategoryRepository;
import com.solo.sell.service.ProductCategoryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * 类目服务实现
 */
@Service
public class ProductCategoryServiceImpl implements ProductCategoryService {

    @Autowired
    ProductCategoryRepository repository;

    @Override
    public ProductCategory findOne(Integer id) {
        return repository.findById(id).get();
    }

    @Override
    public List<ProductCategory> findAll() {
        return repository.findAll();
    }

    @Override
    public ProductCategory save(ProductCategory productCategory) {
        return repository.save(productCategory);
    }

    @Override
    public List<ProductCategory> findByCategoryTypeIn(List<Integer> types) {
        return repository.findByCategoryTypeIn(types);
    }
}

四、单元测试

ProductCategoryRepositoryProductCategoryServiceImpl 都编写单元测试。

ProductCategoryRepository 的单元测试:

代码语言:javascript复制
@RunWith(SpringRunner.class)
@SpringBootTest
public class ProductCategoryRepositoryTest {

<span class="hljs-meta">@Autowired</span>
<span class="hljs-keyword">private</span> ProductCategoryRepository repository;

<span class="hljs-meta">@Test</span>
<span class="hljs-meta">@Transactional</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">add</span><span class="hljs-params">()</span> </span>{
    ProductCategory category = <span class="hljs-keyword">new</span> ProductCategory(<span class="hljs-string">"女生最爱"</span>, <span class="hljs-number">1</span>);
    ProductCategory save = repository.save(category);
    Assert.assertNotNull(save);
}

<span class="hljs-meta">@Test</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">findOne</span><span class="hljs-params">()</span> </span>{
    ProductCategory productCategory = repository.findById(<span class="hljs-number">1</span>).get();
    Assert.assertNotNull(productCategory);
}

<span class="hljs-meta">@Test</span>
<span class="hljs-meta">@Transactional</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">update</span><span class="hljs-params">()</span> </span>{
    ProductCategory category = repository.findById(<span class="hljs-number">1</span>).get();
    category.setCategoryType(<span class="hljs-number">4</span>);
    ProductCategory save = repository.save(category);
    Assert.assertNotNull(save);
}

<span class="hljs-comment">/**
 * 传入类型列表,查询包含列表中类型的所有数据
 */</span>
<span class="hljs-meta">@Test</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">findByCategoryType</span><span class="hljs-params">()</span> </span>{
    List&lt;Integer&gt; types = Arrays.asList(<span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>);
    List&lt;ProductCategory&gt; list = repository.findByCategoryTypeIn(types);
    Assert.assertNotEquals(<span class="hljs-number">0</span>, list.size());
}

}

ProductCategoryServiceImpl 的单元测试:

代码语言:javascript复制
@RunWith(SpringRunner.class)
@SpringBootTest
public class ProductCategoryServiceImplTest {

    @Autowired
    ProductCategoryServiceImpl service;

    @Test
    public void findOne() {
        ProductCategory one = service.findOne(1);
        Assert.assertEquals(new Integer(1), one.getCategoryId());
    }

    @Test
    public void findAll() {
        List<ProductCategory> list = service.findAll();
        Assert.assertNotEquals(0, list.size());
    }

    @Test
    public void save() {
        ProductCategory cate = service.save(new ProductCategory("热销榜", 5));
        Assert.assertNotNull(cate);
    }

    @Test
    public void findByCategoryTypeIn() {
        List<ProductCategory> list = service.findByCategoryTypeIn(Arrays.asList(3, 4, 5, 6));
        Assert.assertNotEquals(0, list.size());
    }
}

注意:在测试方法上加注解 @Transactional ,会在测试之后把测试中操作的数据库全部回滚,不会因为测试污染数据库。

今天就到这,下次见~

源码地址:https://github.com/cachecats/sell

0 人点赞