Spring boot使用一个接口实现任意一张表的增删改查

Spring boot使用一个接口实现任意一张表的增删改查

本文旨在:

  • (需要做额外的操作创建对应表和再一个配置表里配置相关的表)

  • 使用一个接口的方式,下载任意一个表的Excel模板

  • 使用一个接口的方式,将任意的excel中的数据导入到对应的表里面

  • 使用一个接口的方式,将任意表中的数据查询出来并展示

  • 使用一个接口的方式,将任意表中的数据查询出来并根据表中字段自动生成过滤条件展示

  • 使用一个接口的方式,对于任意表中的数据进行新增

  • 使用一个接口的方式,对任意表中的任意数量数据删除

  • 使用一个接口的方式,对任意表中的任意一条数据进行修改

这个是我之前开发项目的时候遇到自定义数据CRUD时写的解决方案,因为觉得不错,所以把其中的业务部份的逻辑都剔除了,提取出了其中的重要的部分,用于帮助分享

0、讲解部分

首先为了保证数据的唯一性,我默认每一张自动定义的表里面肯定有一个相同的属性名字的属,这个属性一定是主键

另外就是我会单独的存储不同表的过滤条件。这个过滤条件可以手动加,也可以写接口帮助加。在自动创建表提交表单时就可以往过滤的表中存储这样的过滤字段

不过由于时间原因,我并没有写通过一个接口的方式可以创建这样的表的接口,如果大家有空的话可以写一下帮我加上代码

我会把带代码提交到GitHub中,是免费开源的

相应的这个博客解答了我在这个博客中抛给大家的问题《Spring boot结合easy excel实现低代码量的Excel导入导出》

1、准备工作

引入maven依赖

<dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.10</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.83</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.2</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.5.2</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.6</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
            <version>3.5.1</version>
        </dependency>
        <!--引入Knife4j的官方start包,该指南选择Spring Boot版本<3.0,开发者需要注意-->
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-openapi2-spring-boot-starter</artifactId>
            <version>4.4.0</version>
        </dependency>

        <!-- 参数校验依赖 -->
        <dependency>
            <groupId>org.hibernate.validator</groupId>
            <artifactId>hibernate-validator</artifactId>
        </dependency>

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

        <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.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.25</version>
            <scope>compile</scope>
        </dependency>

其中主要是一下一些配置信息:

druid、knife4j、fastjson、mybatis-plus、动态数据源、MySQL驱动、lombok、hutool

我们使用的是spring boot 是2.5.6版本。

初始化SQL

create schema IF NOT EXISTS report collate utf8mb4_general_ci;
use
report;

create table if not exists report.filter_info
(
    id          bigint            not null comment '主键',
    table_code  varchar(100)      null comment '表编码',
    column_code varchar(100)      null comment '字段码',
    column_name varchar(100)      null comment '字段名称',
    type        varchar(32)       null comment '类型',
    dim_class   varchar(100)      null comment '对应维度值',
    sort        int               null comment '排序',
    is_required tinyint default 0 null comment '是否必须'
    ) comment '表筛选项表';

create table if not exists report.meta_info_mapping
(
    sys_code      varchar(100) null comment '元数据编码',
    sys_name      varchar(100) null comment '元数据名称',
    sys_dim_class varchar(100) null comment '元数据类型'
    ) comment '元数据<下拉框使用>';

配置文件信息为

spring:
  application:
    name: xxxx
  datasource:
    dynamic:
      # ?????
      primary: master
      datasource:
        master:
          driver-class-name: com.mysql.cj.jdbc.Driver
          url: jdbc:mysql://127.0.0.1:3306/report?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true
          username: root
          password: 123456
      druid:
        initialSize: 10
        minIdle: 10
        maxActive: 200
        max-wait: 60000
        pool-prepared-statements: true
        max-pool-prepared-statement-per-connection-size: 20
        validation-query: SELECT 'x'
        test-on-borrow: false
        test-on-return: false
        test-while-idle: true
        time-between-eviction-runs-millis: 60000  #???????????????????????????????
        min-evictable-idle-time-millis: 300000    #??????????????????????
        filters: stat,wall
        wall:
          comment-allow: true
          multiStatementAllow: true
          noneBaseStatementAllow: true
knife4j:
  enable: true

# mybatis config
mybatis-plus:
  mapper-locations: mapper/*.xml
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

2、代码实现

前后端对接包装类

@Getter
@Setter
@SuppressWarnings("ALL")
@Accessors(chain = true)
public class Result<T> {
    public static final String DEF_ERROR_MESSAGE = "系统繁忙,请稍候再试";
    public static final String HYSTRIX_ERROR_MESSAGE = "请求超时,请稍候再试";
    public static final int SUCCESS_CODE = 200;
    public static final int FAIL_CODE = 500;
    public static final int TIMEOUT_CODE = 503;
    /**
     * 统一参数验证异常
     */
    public static final int VALID_EX_CODE = 400;
    public static final int OPERATION_EX_CODE = 400;
    /**
     * 调用是否成功标识,0:成功,-1:系统繁忙,此时请开发者稍候再试 详情见[ExceptionCode]
     */
    @ApiModelProperty(value = "响应编码:0/200-请求处理成功")
    private int state;

    /**
     * 调用结果
     */
    @ApiModelProperty(value = "响应数据")
    private T data;

    /**
     * 结果消息,如果调用成功,消息通常为空T
     */
    @ApiModelProperty(value = "提示消息")
    private String msg = "SUCCESS";

    /**
     * 附加数据
     */
    // @ApiModelProperty(value = "附加数据")
    // private Map<Object, Object> extra;

    /**
     * 响应时间
     */
    @ApiModelProperty(value = "响应时间戳")
    private long timestamp = System.currentTimeMillis();

    /**
     * 系统报错时,抛出的原生信息
     */
    @ApiModelProperty(value = "异常消息")
    private String errorMsg = null;

    private Result() {
        this.timestamp = System.currentTimeMillis();
    }

    public Result(int code, T data, String msg) {
        this.state = code;
        this.data = data;
        this.msg = msg;
        this.timestamp = System.currentTimeMillis();
    }

    public Result(int code, T data, String msg, String errorMsg) {
        this(code, data, msg);
        this.errorMsg = errorMsg;
    }

    public Result(String message, Object data, String msg) {
    }

    public Result(String message, Object data, String message1, String errorMsg) {
    }

    public static <E> Result<E> result(int code, E data, String msg) {
        return new Result<>(code, data, msg);
    }

    public static <E> Result<E> result(int code, E data, String msg, String errorMsg) {
        return new Result<>(code, data, msg, errorMsg);
    }

    /**
     * 请求成功消息
     *
     * @param data 结果
     * @return RPC调用结果
     */
    public static <E> Result<E> success(E data) {
        return new Result<>(SUCCESS_CODE, data, "SUCCESS");
    }

    public static Result<Boolean> success() {
        return new Result<>(SUCCESS_CODE, true, "SUCCESS");
    }


    public static <E> Result<E> successDef(E data) {
        return new Result<>(SUCCESS_CODE, data, "SUCCESS");
    }

    public static <E> Result<E> successDef() {
        return new Result<>(SUCCESS_CODE, null, "SUCCESS");
    }

    public static <E> Result<E> successDef(E data, String msg) {
        return new Result<>(SUCCESS_CODE, data, msg);
    }

    /**
     * 请求成功方法 ,data返回值,msg提示信息
     *
     * @param data 结果
     * @param msg  消息
     * @return RPC调用结果
     */
    public static <E> Result<E> success(E data, String msg) {
        return new Result<>(SUCCESS_CODE, data, msg);
    }

    /**
     * 请求失败消息
     *
     * @param msg
     * @return
     */
    public static <E> Result<E> fail(int code, String msg) {
        return new Result<>(code, null, (msg == null || msg.isEmpty()) ? DEF_ERROR_MESSAGE : msg);
    }

    public static <E> Result<E> fail(int code, String msg, String errorMsg) {
        return new Result<>(code, null, (msg == null || msg.isEmpty()) ? DEF_ERROR_MESSAGE : msg, errorMsg);
    }

    public static <E> Result<E> fail(String msg) {
        return fail(OPERATION_EX_CODE, msg);
    }

    public static <E> Result<E> fail(String msg, Object... args) {
        String message = (msg == null || msg.isEmpty()) ? DEF_ERROR_MESSAGE : msg;
        return new Result<>(OPERATION_EX_CODE, null, String.format(message, args));
    }

    public static <E> Result<E> fail(Exception exception, String errorMsg) {
        if (exception == null) {
            return fail(DEF_ERROR_MESSAGE);
        }
        return new Result<>(exception.getMessage(), null, exception.getMessage(), errorMsg);
    }

    /**
     * 请求失败消息,根据异常类型,获取不同的提供消息
     *
     * @param throwable 异常
     * @return RPC调用结果
     */
    public static <E> Result<E> fail(Throwable throwable) {
        String msg = throwable != null ? throwable.getMessage() : DEF_ERROR_MESSAGE;
        return fail(FAIL_CODE, msg, msg);
    }

    public static <E> Result<E> validFail(String msg) {
        return new Result<>(VALID_EX_CODE, null, (msg == null || msg.isEmpty()) ? DEF_ERROR_MESSAGE : msg);
    }

    public static <E> Result<E> validFail(String msg, Object... args) {
        String message = (msg == null || msg.isEmpty()) ? DEF_ERROR_MESSAGE : msg;
        return new Result<>(VALID_EX_CODE, null, String.format(message, args));
    }

    public static <E> Result<E> validFail(Exception exceptionCode) {
        return new Result<>(exceptionCode.getMessage(), null,
                (exceptionCode.getMessage() == null || exceptionCode.getMessage().isEmpty()) ? DEF_ERROR_MESSAGE : exceptionCode.getMessage());
    }

    public static <E> Result<E> timeout() {
        return fail(TIMEOUT_CODE, HYSTRIX_ERROR_MESSAGE);
    }

    public Boolean getIsSuccess() {
        return this.state == SUCCESS_CODE || this.state == 0;
    }

    @Override
    public String toString() {
        return JSON.toJSONString(this);
    }
}

model部分

@ApiModel("筛选条件DTO")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class FilterDTO {
    @ApiModelProperty("字段code")
    private String columnCode;
    @ApiModelProperty("值")
    private String value;
    @ApiModelProperty("类型-INPUT:输入框;TIME:时间选择器;TIMEAREA:时间段选择器;SELECT:下拉选择;NUMBER:数字")
    private String type;
    @ApiModelProperty("起始时间(时间、时间段专用)")
    private String startTime;
    @ApiModelProperty("结束时间(时间段专用)")
    private String endTime;
}
@Data
@Builder
@NoArgsConstructor
@ToString(callSuper = true)
@Accessors(chain = true)
@TableName("filter_info")
@AllArgsConstructor
public class FilterInfo {

    private static final long serialVersionUID = 1L;

    @ApiModelProperty(value = "主键")
    @TableId(value = "id")
    protected Long id;

    /**
     * 表编码
     */
    private String tableCode;

    /**
     * 字段码
     */
    private String columnCode;

    /**
     * 字段名称
     */
    private String columnName;

    /**
     * 类型
     */
    private String type;

    /**
     * 对应维度值
     */
    private String dimClass;

    /**
     * 排序
     */
    private Integer sort;
    /**
     * 是否必须
     */
    private String isRequired;
}
@ApiModel("筛选条件VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class FilterVO {
    @ApiModelProperty("字段code")
    private String columnCode;
    @ApiModelProperty("字段名称")
    private String columnName;
    @ApiModelProperty("类型-INPUT:输入框;DATE:日期选择器;DATERANGE:日期段;DATETIME:时间选择器;DATETIMERANGE:时间段;SELECT:下拉选择;NUMBER:数字")
    private String type;
    @ApiModelProperty("下拉字典")
    private List<TupleVO> info;
    @ApiModelProperty("是否必须")
    private String isRequired;
}
@ApiModel("表头及筛选条件VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Alias("HeaderVO")
public class HeaderVO {
    @ApiModelProperty("表头")
    private List<TupleVO> header;
    @ApiModelProperty("筛选条件")
    private List<FilterVO> filter;
}
@ApiModel("新增数据DTO")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class ReportAddDTO {
    @ApiModelProperty(value = "表编码", required = true)
    @NotBlank(message = "表编码不能为空")
    private String tableCode;

    @ApiModelProperty(value = "内容", required = true)
    @NotEmpty(message = "内容不能为空")
    private LinkedHashMap<String, String> info;

}
@ApiModel("删除数据DTO")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class ReportDelDTO {
    @ApiModelProperty(value = "表编码", required = true)
    @NotBlank(message = "表编码不能为空")
    private String tableCode;

    @ApiModelProperty(value = "记录的id值", required = true)
    @NotEmpty(message = "id不能为空")
    private List<String> ids;
}
@ApiModel("修改数据DTO")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class ReportEditDTO {
    @ApiModelProperty(value = "表编码", required = true)
    @NotBlank(message = "表编码不能为空")
    private String tableCode;

    @ApiModelProperty(value = "内容", required = true)
    @NotEmpty(message = "内容不能为空")
    private LinkedHashMap<String, String> info;
}
@ApiModel("上报分页列表DTO")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class ReportListDTO {
    @ApiModelProperty("页码")
    private Integer page;

    @ApiModelProperty("每页数量")
    private Integer size;

    public Integer getPage() {
        return page == null ? 1 : page;
    }

    public Integer getSize() {
        return size == null ? 10 : size;
    }

    @ApiModelProperty(value = "表编码", required = true)
    @NotBlank(message = "表编码不能为空")
    private String tableCode;

    @ApiModelProperty("筛选项")
    private List<FilterDTO> filter;
}
@ApiModel("三元组VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class TupleVO {

    @ApiModelProperty("X轴")
    private String key;

    @ApiModelProperty("图例")
    private String item;

    @ApiModelProperty("Y轴")
    private String value;
}

Controller

@Slf4j
@Api(tags = "首页模块")
@RestController
@Validated
public class MyController {

    @Resource
    private MyService myService;

    @ApiOperationSupport(order = 1)
    @GetMapping("/getHeader")
    @ApiOperation("获取表头及筛选条件")
    public Result<HeaderVO> getHeader(@NotBlank(message = "表编码不能为空")
                                      @RequestParam("tableCode") String tableCode) {
        return Result.success(myService.getHeader(tableCode));
    }

    @ApiOperationSupport(order = 2)
    @PostMapping("/getData")
    @ApiOperation("分页获取表数据")
    public Result<IPage<LinkedHashMap<String, String>>> getData(@Valid @RequestBody ReportListDTO param) {
        return Result.success(myService.getData(param));
    }

    @ApiOperationSupport(order = 3)
    @PostMapping("/addOne")
    public Result<?> addOne(@Valid @RequestBody ReportAddDTO param) {
        return myService.addOne(param) ? Result.success(null, "操作成功") : Result.fail("操作失败");
    }

    @ApiOperation("修改一条数据")
    @ApiOperationSupport(order = 4)
    @PostMapping("/edit")
    public Result<?> edit(@Valid @RequestBody ReportEditDTO param) {
        return myService.edit(param) ? Result.success(null, "操作成功") : Result.fail("操作失败");
    }

    @ApiOperation("删除记录(支持批量)")
    @ApiOperationSupport(order = 5)
    @PostMapping("/del")
    public Result<?> del(@Valid @RequestBody ReportDelDTO param) {
        return myService.del(param) ? Result.success(null, "操作成功") : Result.fail("操作失败");
    }

    @ApiOperation("下载导入模板")
    @ApiOperationSupport(order = 6)
    @GetMapping("/getTemplate")
    public void getTemplate(@ApiParam(value = "表编码", required = true)
                            @NotBlank(message = "表编码不能为空")
                            @RequestParam("tableCode") String tableCode, HttpServletResponse response) {
        myService.getTemplate(tableCode, response);
    }

    @ApiOperation("数据导入")
    @ApiOperationSupport(order = 7)
    @PostMapping("/importData")
    public Result<?> importData(@ApiParam(value = "表编码", required = true)
                                @NotBlank(message = "表编码不能为空")
                                @RequestParam("tableCode") String tableCode,
                                @ApiParam(value = "上传的文件", required = true)
                                @NotNull(message = "上传文件不能为空") MultipartFile file) {
        return myService.importData(tableCode, file) ? Result.success(null, "导入成功") : Result.fail("导入失败");
    }
}

Service

public interface FilterService extends IService<FilterInfo> {

}
@Slf4j
@Service
public class FilterServiceImpl extends ServiceImpl<FilterMapper, FilterInfo> implements FilterService {

}
@Slf4j
@Service
public class MyService {

    private static final String ONLY_KEY = "only_key";

    @Resource
    private MyMapper dao;

    @Resource
    private FilterServiceImpl filterInfoService;

    public void getTemplate(String tableCode, HttpServletResponse response) {
        try (ExcelWriter writer = ExcelUtil.getWriter(true)) {
            response.setCharacterEncoding("UTF-8");
            List<List<String>> data = new ArrayList<>();
            List<String> result = dao.getTemplate(tableCode);
            data.add(result);
            // 一次性写出内容,使用默认样式,强制输出标题
            writer.write(data, true);
            ServletOutputStream out = null;
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(tableCode, "UTF-8") + ".xlsx");
            out = response.getOutputStream();
            writer.flush(out, true);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public HeaderVO getHeader(String tableCode) {
        HeaderVO result = new HeaderVO();
        List<FilterInfo> headers = filterInfoService.list(new LambdaQueryWrapper<FilterInfo>()
                .eq(FilterInfo::getTableCode, tableCode)
                .orderByAsc(FilterInfo::getSort)
        );
        List<TupleVO> headList = new ArrayList<>();
        List<FilterVO> filterList = new ArrayList<>();
        for (FilterInfo header : headers) {
            //存放表头信息
            headList.add(new TupleVO(header.getColumnCode(), header.getIsRequired(), header.getColumnName()));
            //获取特殊组件字典信息
            List<TupleVO> dimList = new ArrayList<>();
            if (header.getType().equals("select")) {
                dimList = dao.getDimList(header.getDimClass());
            }
            filterList.add(FilterVO.builder()
                    .columnCode(header.getColumnCode())
                    .columnName(header.getColumnName())
                    .type(header.getType())
                    .isRequired(header.getIsRequired())
                    .info(dimList)
                    .build());
        }
        result.setHeader(headList);
        result.setFilter(filterList);
        return result;
    }

    public IPage<LinkedHashMap<String, String>> getData(ReportListDTO param) {
        return dao.getData(new Page<>(param.getPage(), param.getSize()), param);
    }

    public boolean addOne(ReportAddDTO param) {
        Assert.isTrue(!param.getInfo().isEmpty(), "参数列表不能为空");
        Assert.isTrue(param.getInfo().containsKey(ONLY_KEY), "主键不存在");
        param.getInfo().put(ONLY_KEY, IdUtil.simpleUUID());
        return dao.addOne(param);
    }

    @Transactional(rollbackFor = Exception.class)
    public boolean edit(ReportEditDTO param) {
        Assert.isTrue(!param.getInfo().isEmpty(), "参数列表不能为空");
        Assert.isTrue(param.getInfo().containsKey(ONLY_KEY), "主键不存在");
        String id = param.getInfo().get(ONLY_KEY);
        param.getInfo().remove(ONLY_KEY);
        return dao.edit(id, param);
    }

    @Transactional(rollbackFor = Exception.class)
    public boolean del(ReportDelDTO param) {
        return dao.del(param);
    }


    public boolean importData(String tableCode, MultipartFile file) {
        try {
            ExcelReader reader = ExcelUtil.getReader(file.getInputStream());
            List<List<Object>> list = reader.read();

            int index = -1;
            for (int k = 0; k < list.get(0).size(); k++) {
                if (ONLY_KEY.equals(list.get(0).get(k))) {
                    index = k;
                    break;
                }
            }
            Assert.isTrue(index >= 0, "缺少主键");
            //去掉标题行
            list.remove(0);
            for (int i = 0; i < list.size(); i++) {
                for (int j = 0; j < list.get(i).size(); j++) {
                    if (j == index) {
                        list.get(i).set(j, IdUtil.simpleUUID());
                        break;
                    }
                }
            }
            dao.importData(tableCode, list);
        } catch (Exception e) {
            log.info(e.getMessage());
            return false;
        }
        return true;
    }
}

Mapper

@Mapper
public interface FilterMapper extends BaseMapper<FilterInfo> {

}
@Mapper
public interface MyMapper {

    List<String> getTemplate(@Param("tableCode") String tableCode);

    List<TupleVO> getDimList(@Param("dimClass") String dimClass);

    IPage<LinkedHashMap<String, String>> getData(Page<LinkedHashMap<String, String>> objectPage, @Param("param") ReportListDTO param);

    boolean addOne(@Param("param") ReportAddDTO param);

    void importData(@Param("tableCode") String tableCode, @Param("list") List<List<Object>> list);

    boolean edit(@Param("id") String id, @Param("param") ReportEditDTO param);

    boolean del(@Param("param") ReportDelDTO param);

}

Mapper的xml部分

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.chashugu.lowcodecrud.MyMapper">

    <select id="getTemplate" resultType="java.lang.String">
        select column_name
        FROM information_schema.columns
        WHERE table_schema = 'xxxx'
          AND table_name = #{tableCode}
    </select>

    <select id="getDimList" resultType="com.chashugu.lowcodecrud.model.TupleVO">
        select sys_code `key`, sys_name 'value'
        from meta_info_mapping
        where sys_dim_class = #{dimClass}
        order by cast(sys_code as signed)
    </select>

    <select id="getData" resultType="java.util.LinkedHashMap">
        select t1.*
        from ${param.tableCode} t1
        <where>
            <if test="param.filter != null">
                <foreach collection="param.filter" item="item" separator=" ">
                    <choose>
                        <when test="item.columnCode == 'push_flag'">
                        </when>
                        <when test="item.columnCode == 'approval_flag'">
                        </when>
                        <otherwise>
                            <choose>
                                <when test="item.type == 'DATE'">
                                    <if test="item.startTime != null">
                                        and date(t1.${item.columnCode}) = date(#{item.startTime})
                                    </if>
                                </when>
                                <when test="item.type == 'DATERANGE'">
                                    <if test="item.startTime != null and item.endTime != null">
                                        and date(t1.${item.columnCode}) between date(#{item.startTime}) and
                                        date(#{item.endTime})
                                    </if>
                                </when>
                                <when test="item.type == 'DATETIME'">
                                    <if test="item.startTime != null">
                                        and str_to_date(t1.${item.columnCode},'%Y%m%d %H%i%s') =
                                        timestamp(#{item.startTime})
                                    </if>
                                </when>
                                <when test="item.type == 'DATETIMERANGE'">
                                    <if test="item.startTime != null and item.endTime != null">
                                        and str_to_date(t1.${item.columnCode},'%Y%m%d %H%i%s') between
                                        timestamp(#{item.startTime}) and timestamp(#{item.endTime})
                                    </if>
                                </when>
                                <otherwise>
                                    <if test="item.value != null and item.value != ''">
                                        and t1.${item.columnCode}=#{item.value}
                                    </if>
                                </otherwise>
                            </choose>
                        </otherwise>
                    </choose>

                </foreach>
            </if>
        </where>
    </select>

    <insert id="addOne">
        insert into ${param.tableCode}
        (
        <foreach collection="param.info" index="col" separator=",">
            ${col}
        </foreach>
        )
        values
        (
        <foreach collection="param.info" item="value" separator=",">
            #{value}
        </foreach>
        )
    </insert>

    <update id="edit">
        update ${param.tableCode}
        set
        <foreach collection="param.info" index="key" item="value" separator=",">
            ${key}=#{value}
        </foreach>
        where only_key=#{id}
    </update>

    <delete id="del">
        delete from ${param.tableCode}
        where only_key in
        <foreach collection="param.ids" open="(" close=")" item="item" separator=",">
            #{item}
        </foreach>
    </delete>

    <insert id="importData">
        insert into ${tableCode}
        values
        <foreach collection="list" item="item" separator=",">
            (
            <foreach collection="item" item="data" separator=",">
                #{data}
            </foreach>
            )
        </foreach>
    </insert>
</mapper>
  • 6
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: 好的,下面是一个使用 Spring Boot 实现的简单的增删改查示例,具体实现如下: 首先,我们需要创建一个 `User` 实体类,用于存储用户信息: ```java @Entity @Table(name = "user") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(name = "username") private String username; @Column(name = "password") private String password; @Column(name = "email") private String email; // 省略 getter 和 setter 方法 } ``` 接下来,我们需要创建一个 `UserRepository` 接口,继承自 `JpaRepository`,用于定义对 `User` 实体类的增删改查操作: ```java @Repository public interface UserRepository extends JpaRepository<User, Long> { } ``` 然后,我们需要创建一个 `UserController` 类,用于处理与用户相关的 HTTP 请求: ```java @RestController @RequestMapping("/users") public class UserController { @Autowired private UserRepository userRepository; @GetMapping("/") public List<User> getAllUsers() { return userRepository.findAll(); } @GetMapping("/{id}") public User getUserById(@PathVariable Long id) { return userRepository.findById(id).orElse(null); } @PostMapping("/") public User createUser(@RequestBody User user) { return userRepository.save(user); } @PutMapping("/{id}") public User updateUser(@PathVariable Long id, @RequestBody User user) { Optional<User> optionalUser = userRepository.findById(id); if (optionalUser.isPresent()) { User existingUser = optionalUser.get(); existingUser.setUsername(user.getUsername()); existingUser.setPassword(user.getPassword()); existingUser.setEmail(user.getEmail()); return userRepository.save(existingUser); } else { return null; } } @DeleteMapping("/{id}") public void deleteUser(@PathVariable Long id) { userRepository.deleteById(id); } } ``` 最后,我们需要在 `Application` 类中启用 JPA 和 REST 服务: ```java @SpringBootApplication @EnableJpaRepositories(basePackages = "com.example.demo.repository") public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } ``` 现在,我们就可以测试我们的增删改查服务了。例如,我们可以使用 `curl` 命令来测试: ```bash # 获取所有用户 $ curl http://localhost:8080/users/ # 根据 ID 获取用户 $ curl http://localhost:8080/users/1 # 创建用户 $ curl -X POST -H "Content-Type: application/json" -d '{"username":"admin", "password":"admin123", "email":"admin@example.com"}' http://localhost:8080/users/ # 更新用户 $ curl -X PUT -H "Content-Type: application/json" -d '{"username":"admin", "password":"admin456", "email":"admin@example.com"}' http://localhost:8080/users/1 # 删除用户 $ curl -X DELETE http://localhost:8080/users/1 ``` ### 回答2: 使用Spring Boot编写一个简单的增删改查(CRUD)应用程序非常简单。以下是一个基本的示例: 首先,我们需要配置一个Spring Boot项目,包括添加Spring Boot依赖项以及创建一个启动类。可以使用Maven或Gradle来管理构建和依赖项。 然后,创建一个实体类,示数据库中的数据。该实体类应该使用JPA注解来标识、列和关系等信息。 接下来,创建一个数据访问对象(DAO)接口,继承自JpaRepository接口,并在其中定义需要的增删改查方法。 Spring Data JPA会根据方法名生成相应的SQL查询。 然后,创建一个包含业务逻辑的服务类,实现相应的增删改查方法。在该类中,可以注入DAO接口,以便与数据库进行交互。 最后,创建一个控制器类,用于处理HTTP请求和响应。在该类中,注入服务类,将HTTP请求转发到相应的服务方法,并将结果返回给客户端。 通过以上步骤,我们就可以实现一个简单的增删改查功能的Spring Boot应用程序了。可以使用Postman或类似工具来测试应用程序的功能。 ### 回答3: 使用Spring Boot编写一个简单的增删改查操作可以参考以下步骤: 1. 首先,创建一个Spring Boot项目并添加所需的依赖,包括Spring Boot Web、Spring Data JPA和H2数据库等。 2. 创建一个实体类,示数据库中的。例如,可以创建一个名为User的实体类,包含id、name和age等属性,同时添加相应的构造方法、getter和setter方法。 3. 创建一个用于处理HTTP请求的Controller类。通过注解将该类标记为控制器,并使用@Autowired注解将实体类的数据访问对象(Repository)注入到控制器中。 4. 在Controller类中创建用于处理增删改查请求的方法,通过注解指定访问路径和请求方法。例如,可以创建一个用于查询所有用户的方法,并返回JSON格式的数据。该方法可以使用Repository提供的findAll()方法来获取所有用户数据。 5. 同样,在Controller类中创建其他增删改查操作的方法。例如,创建一个用于按id查询用户的方法,可以使用Repository提供的findById()方法,并返回JSON格式的数据。 6. 在Controller类中创建用于处理创建新用户的方法。可以使用Repository提供的save()方法将新用户保存到数据库中。 7. 类似地,可以创建用于更新和删除用户数据的方法,使用Repository提供的save()和delete()方法来更新或删除数据库中的用户数据。 8. 配置应用程序的数据库连接信息,例如用户名、密码、连接URL等。 9. 运行Spring Boot应用程序,并使用Postman或其他工具发送HTTP请求来测试增删改查操作的功能。可以使用GET、POST、PUT和DELETE方法来测试不同的操作。 通过以上步骤,可以快速使用Spring Boot编写一个简单的增删改查功能。需要根据具体的需求和数据库结构进行相应的调整,并添加适当的数据校验和错误处理,以确保应用程序的稳定性和健壮性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值