本文转自测试人社区,原文链接:https://ceshiren.com/t/topic/30757

一,springBoot项目 导入依赖

<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.junit.jupiter</groupId>
			<artifactId>junit-jupiter-api</artifactId>
			<version>5.8.2</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<version>RELEASE</version>
			<scope>compile</scope>
		</dependency>
		<dependency>
			<groupId>com.fasterxml.jackson.dataformat</groupId>
			<artifactId>jackson-dataformat-xml</artifactId>
			<version>2.13.1</version>
		</dependency>
		<!-- mysql连接 -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>8.0.29</version>
		</dependency>
		<!--mybatis坐标-->
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis</artifactId>
			<version>3.5.9</version>
		</dependency>
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>2.1.0</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/tk.mybatis/mapper-spring-boot-starter -->
		<dependency>
			<groupId>tk.mybatis</groupId>
			<artifactId>mapper-spring-boot-starter</artifactId>
			<version>2.1.5</version>
		</dependency>
		<dependency>
			<groupId>io.springfox</groupId>
			<artifactId>springfox-boot-starter</artifactId>
			<version>3.0.0</version>
		</dependency>
		<dependency>
			<groupId>org.mapstruct</groupId>
			<artifactId>mapstruct</artifactId>
			<version>1.4.2.Final</version>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
			<plugin>
				<groupId>org.mybatis.generator</groupId>
				<artifactId>mybatis-generator-maven-plugin</artifactId>
				<version>1.3.7</version>
				<!--插件设置-->
				<configuration>
					<!--允许移动生成的文件-->
					<verbose>true</verbose>
					<!--启用覆盖-->
					<overwrite>true</overwrite>
					<!--自动生成配置 如果名字是generatorConfig.xml可以省略配置-->
					<configurationFile>src/main/resources/generator/generatorConfig.xml</configurationFile>
				</configuration>
				<dependencies>
					<dependency>
						<groupId>mysql</groupId>
						<artifactId>mysql-connector-java</artifactId>
						<version>8.0.29</version>
						<scope>runtime</scope>
					</dependency>
					<dependency>
						<groupId>tk.mybatis</groupId>
						<artifactId>mapper</artifactId>
						<version>4.1.5</version>
					</dependency>
				</dependencies>
			</plugin>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.8.1</version>
				<configuration>
					<source>12</source>
					<target>12</target>
					<annotationProcessorPaths>
						<path>
							<groupId>org.mapstruct</groupId>
							<artifactId>mapstruct-processor</artifactId>
							<version>1.4.2.Final</version>
						</path>
					</annotationProcessorPaths>
				</configuration>
			</plugin>
		</plugins>
	</build>

<!--	<profiles>-->
<!--		<profile>-->
<!--			<id>dev</id>-->
<!--			<properties>-->
<!--				<profilesActive>dev</profilesActive>-->
<!--			</properties>-->
<!--		</profile>-->
<!--		<profile>-->
<!--			<id>test</id>-->
<!--			<properties>-->
<!--				<profilesActive>test</profilesActive>-->
<!--			</properties>-->
<!--			<activation>-->
<!--				<!–				设置为默认环境的配置–>-->
<!--				<activeByDefault>true</activeByDefault>-->
<!--			</activation>-->
<!--		</profile>-->
<!--	</profiles>-->

</project>

二, 配置数据源(application.yml文件为例)

#spring数据库连接配置
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://10.52.46.11:33066/advert
    username: mysql
    password: 123456
  #Swagger页面展示内容配置
  mvc:
    pathmatch:
      matching-strategy: ANT_PATH_MATCHER

三,添加mapper扫描路径(加上MapperScan注解)

package com.oppo.advertSpring;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import tk.mybatis.spring.annotation.MapperScan;

@SpringBootApplication
@MapperScan("com.oppo.advertSpring.mapper")
public class AdvertSpringApplication {
	public static void main(String[] args) {
		SpringApplication.run(AdvertSpringApplication.class, args);
	}

}

四,配置mybatis相关依赖(application.yml文件为例)

#mybatis连接配置
mybatis:
  configuration:
    use-actual-param-name: true
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.oppo.advertSpring.entity

五,Bean拷贝实现

5.1 Bean拷贝实现的背景及解决方法

背景:

  • 前端通过接口直接操作数据库表的实体类对象,对应的字段都暴露出来,数据库字段数据泄密风险

解决方法:

  • (1)使用自定义的dto进行业务逻辑编写
  • entityentity 是实体类,会在数据库中存在的实际的表,包括它的每一个字段
  • DTO: 与Controller交互的对象,都当做是DTO对象,dto存储前端传参字段,不透露数据表
  • (2)使用bean拷贝
  • dto的实体类与entity的实体类进行转换
  • bean拷贝:DTOentity转换

5.2 实现工具类 mapstruct

  • 注解处理器
  • 可以生成 JavaBean 之间那的映射代码
  • 类型安全, 高性能, 无依赖性
  • 通过注解的方式帮我们实现 JavaBean 之间的转换

##5.3 mapstruct依赖导入

<dependencies>
              <dependency>
			<groupId>org.mapstruct</groupId>
			<artifactId>mapstruct</artifactId>
			<version>1.4.2.Final</version>
		</dependency>
	</dependencies>

   <build>
    <plugins>
           <plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
                                <version>3.8.1</version>
				<configuration>
					<source>12</source>
					<target>12</target>
					<annotationProcessorPaths>
						<path>
							<groupId>org.mapstruct</groupId>
							<artifactId>mapstruct-processor</artifactId>
							<version>1.4.2.Final</version>
						</path>
					</annotationProcessorPaths>
				</configuration>
			</plugin>
		</plugins>
	</build>

六,编写业务代码

6.1 定义一个dto的实体类,实体类字段根据需要取必要的传参字段,字段少于entity的实体类

package com.oppo.advertSpring.dto;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import javax.persistence.Column;
import javax.persistence.Table;


@ApiModel(value = "精准词表", description = "advert.ads_search_kwctrl")
@Table(name = "ads_search_kwctrl")
public class AdsSearchKwctrlDto {

    /**
     * 应用ID
     */
    @Column(name = "app_id")
    private Integer appId;

    /**
     * 关键词
     */
    private String keyword;

    /**
     * 来源[1运营添加 2广告主添加]
     */
    @ApiModelProperty(value = "来源", allowableValues = "1,2")
    private Integer source;

    public Integer getAppId() {
        return appId;
    }

    public void setAppId(Integer appId) {
        this.appId = appId;
    }

    public String getKeyword() {
        return keyword;
    }

    public void setKeyword(String keyword) {
        this.keyword = keyword;
    }

    public Integer getSource() {
        return source;
    }

    public void setSource(Integer source) {
        this.source = source;
    }

    @Override
    public String toString() {
        return "AdsSearchKwctrlDto{" +
                "appId=" + appId +
                ", keyword='" + keyword + ''' +
                ", source=" + source +
                '}';
    }
}

6.2 定义一个KwctrlService接口,传参为dto的实体类

package com.oppo.advertSpring.service;

import com.oppo.advertSpring.dto.AdsSearchKwctrlDto;
import com.oppo.advertSpring.util.Result;

import java.text.ParseException;

public interface KwctrlService {

    Result insertKwctl(AdsSearchKwctrlDto adsSearchKwctrlDto) throws ParseException;

    Result updateKwctl(AdsSearchKwctrlDto adsSearchKwctrlDto) throws ParseException;

    Result findKwctl(AdsSearchKwctrlDto adsSearchKwctrlDto);

    Result deleteKwctl(AdsSearchKwctrlDto adsSearchKwctrlDto);

}

6.3 创建转换类,实现AdsSearchKwctrl转换成AdsSearchKwctrlDto

  • 使用mapper注解,导入的包为mapstruct的包
  • @Mapper(componentModel = “spring”)
  • 生成的映射器是一个单例范围的 Spring bean,可以通过以下方式检索@Autowired
package com.oppo.advertSpring.converter;

import com.oppo.advertSpring.dto.AdsSearchKwctrlDto;
import com.oppo.advertSpring.entity.AdsSearchKwctrl;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;

@Mapper(componentModel = "spring")
public interface AdsSearchKwctrConverter {
    //    AdsSearchKwctrl转换成AdsSearchKwctrlDto的实现

    @Mappings({
            @Mapping(target = "appId", source = "appId"),
            @Mapping(target = "keyword", source = "keyword"),
            @Mapping(target = "source", source = "source")
    })
    AdsSearchKwctrl dtoForKwctl(AdsSearchKwctrlDto adsSearchKwctrlDto);

}

6.4 创建接口实现类KwctrlServiceImpl

package com.oppo.advertSpring.service;

import com.oppo.advertSpring.converter.AdsSearchKwctrConverter;
import com.oppo.advertSpring.dto.AdsSearchKwctrlDto;
import com.oppo.advertSpring.entity.AdsSearchKwctrl;
import com.oppo.advertSpring.mapper.AdsSearchKwctrlMapper;
import com.oppo.advertSpring.util.Result;
import com.oppo.advertSpring.util.TimestampUtil;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import tk.mybatis.mapper.entity.Example;
import java.text.ParseException;
import java.util.List;

@Service
public class KwctrlServiceImpl implements KwctrlService {

    @Autowired
    AdsSearchKwctrlMapper adsSearchKwctrlMapper;

    @Autowired
    AdsSearchKwctrConverter adsSearchKwctrConverter;

    TimestampUtil time = new TimestampUtil();

//    @SneakyThrows
    @Override
    public Result insertKwctl(AdsSearchKwctrlDto adsSearchKwctrlDto) throws ParseException {
        AdsSearchKwctrl adsSearchKwctrl = adsSearchKwctrConverter.dtoForKwctl(adsSearchKwctrlDto);

        adsSearchKwctrl.setInsertTime(time.timestamp());
        adsSearchKwctrl.setLastModifyTime(time.timestamp());
        int insertNum = adsSearchKwctrlMapper.insert(adsSearchKwctrl);
        System.out.println(insertNum);
        return Result.OK().data(adsSearchKwctrl).message("数据插入成功");
    }


    @Override
    public Result findKwctl(AdsSearchKwctrlDto adsSearchKwctrlDto) {
        AdsSearchKwctrl adsSearchKwctrl = adsSearchKwctrConverter.dtoForKwctl(adsSearchKwctrlDto);
        List<AdsSearchKwctrl> select = adsSearchKwctrlMapper.select(adsSearchKwctrl);
//        AdsSearchKwctrl one = adsSearchKwctrlMapper.selectOne(adsSearchKwctrl);
        System.out.println(select);
        return Result.OK().data(select).message("查找成功");
    }

//    @SneakyThrows
    @Override
    public Result updateKwctl(AdsSearchKwctrlDto adsSearchKwctrlDto) throws ParseException {
        AdsSearchKwctrl adsSearchKwctrl = adsSearchKwctrConverter.dtoForKwctl(adsSearchKwctrlDto);
        //查找条件,相当于select * from ads_search_kwctrl where app_id= and keyword=
        Example example = new Example(AdsSearchKwctrl.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("appId", adsSearchKwctrl.getAppId());

        List<AdsSearchKwctrl> kwctrlList = adsSearchKwctrlMapper.selectByExample(example);
        System.out.println("查找结果的第一条数据:"  + kwctrlList.get(0));
        //获取appId对应的唯一主键
        Integer id = kwctrlList.get(0).getKwctrlId();
        adsSearchKwctrl.setKwctrlId(id);
        //填充最新修改时间
        adsSearchKwctrl.setLastModifyTime(time.timestamp());
        //根据查找结果更新这条数据
        int updateNum = adsSearchKwctrlMapper.updateByPrimaryKeySelective(adsSearchKwctrl);
        System.out.println( "更新数据:"+ updateNum + "条");
        //查询修改后的数据
        AdsSearchKwctrl selectOne = adsSearchKwctrlMapper.selectOne(adsSearchKwctrl);
        System.out.println("更新后的数据:"+selectOne);
        return Result.OK().data(selectOne).message("修改成功");
    }

    
    @Override
    public Result deleteKwctl(AdsSearchKwctrlDto adsSearchKwctrlDto) {
        AdsSearchKwctrl adsSearchKwctrl = adsSearchKwctrConverter.dtoForKwctl(adsSearchKwctrlDto);
        int delete = adsSearchKwctrlMapper.delete(adsSearchKwctrl);
        System.out.println(delete);
        return Result.OK().data(adsSearchKwctrl).message("删除成功");
    }




}

6.5 controller创建对应的接口

package com.oppo.advertSpring.controller;

import com.oppo.advertSpring.dto.AdsSearchKwctrlDto;
import com.oppo.advertSpring.entity.AdsSearchKwctrl;
import com.oppo.advertSpring.service.KwctrlService;
import com.oppo.advertSpring.util.Result;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import java.text.ParseException;

@RestController
public class KwctrlController {

    @Autowired
    KwctrlService kwctrlService;

    @ApiOperation("精准词insert接口")
    @PostMapping(path = "/insertKwctl", produces = "application/json")
    Result insertKwctl(@RequestBody AdsSearchKwctrlDto adsSearchKwctrlDto) throws ParseException {
        return kwctrlService.insertKwctl(adsSearchKwctrlDto);
    }


    @ApiOperation("精准词find接口")
    @PostMapping(path = "/findKwctl", produces = "application/json")
    Result findKwctl(@RequestBody AdsSearchKwctrlDto adsSearchKwctrlDto){
        return kwctrlService.findKwctl(adsSearchKwctrlDto);
    }


    @ApiOperation("精准词update接口")
    @PostMapping(path = "/updateKwctl", produces = "application/json")
    Result updateKwctl(@RequestBody AdsSearchKwctrlDto adsSearchKwctrlDto) throws ParseException {
        return kwctrlService.updateKwctl(adsSearchKwctrlDto);
    }


    @ApiOperation("精准词delete接口")
    @PostMapping(path = "/deleteKwctl", produces = "application/json")
    Result deleteKwctl(@RequestBody AdsSearchKwctrlDto adsSearchKwctrlDto){
        return kwctrlService.deleteKwctl(adsSearchKwctrlDto);
    }

}

6.6 Swagger页面调用接口看是否正常

软件测试学习笔记丨后端架构优化设计 - spring boot 增删改查操作_springboot