脚手架开发必备——代码生成器的实现(varCode_1.0)

codeGenerator

  • 框架研发的程序员们往往提供业务快速开发的脚手架,内置各种工具、技术配置集成,公司自主研发底层框架、以便其他业务部门实现快速开发,无需项目的搭建。其中代码生成器也是因需求自然而生。
  • 提到代码生成器,鼎鼎大名的mybatis-generator也是最早接触的,但仅仅生成pojo、业务、持久层还是mapper文件

varCode_1.0

varCode:自己java代码实现的生成pojo、service、serviceImpl、dao、daoImpl、controller、js、html(js、html模板还未开发完)的前后端一套代码构建工具,无需修改、即刻运行的简单web项目,具体集成的功能下文描述。

设计思路

底层数据库操作——>元数据DatabaseMetaData获取相关表信息(转换为需要生成模板的对象数据)——>模板引擎构建代码生成

从配置项说起
<?xml version="1.0" encoding="UTF-8"?>
<config>
    <!--“/”表示存放于当前项目结构中-->
    <baseDir>/</baseDir>
    <!--生成的包名结构-->
    <basePackage>com.lin.bdp</basePackage>
    <dbName>test</dbName>
    <dbUserName>root</dbUserName>
    <dbPassword></dbPassword>
    <!--“*”代表所有,多个表名用逗号,分割-->
    <tableName>f_user</tableName>
    <dbDriver>com.mysql.jdbc.Driver</dbDriver>
    <bdUrl>jdbc:mysql://localhost:3306/test?useUnicode=true&amp;characterEncoding=utf-8&amp;useSSL=false&amp;serverTimezone=UTC</bdUrl>
</config>

配置项的信息往往取决于功能展示的方式和获取信息的途径:
baseDir:配置物理地址生成代码的路径 ,“/”友善的实现直接存放当前项目
basePackage:项目包名的结构
数据库信息一套
tableName:生成的代码表名,多个“,“分割,”*”友善的实现所有表

提供xml解析工具类(自己用的digester,准备改成properties文件由spring env加载)

需要获取的数据库信息对象

只列举实体类和字段

public class TableInfo {

    private String tableName;

    private String originTableName;//数据库带_命名方式的表名

    private List<ColumnInfo> columnInfoList;

    private ColumnInfo primaryKeyColumn;//主键字段

    private Boolean autoIncrement;/主键增长方式
    }
public class ColumnInfo {

    private String columnName;
    private String originColumnName;
    private String columnType;
    private String remarks;
}

字符串工具类实现:
1、驼峰式命名与数据库命名转换
2、实体类、字段、get方法需要用到的首字母大小写转换
3、数据库字段类型和java属性类型转换

package com.lin.util;


public class StringDBUtil {

    /**
     * 数据库_命名转化为驼峰式命名
     * @param tableOrColumnName
     * @return
     */
    public static String dbNameHandle(String tableOrColumnName){
        if (!tableOrColumnName.contains("_")){
            return tableOrColumnName;
        }
        tableOrColumnName = tableOrColumnName.replaceAll("^\\w_","");
        String old = String.valueOf(tableOrColumnName.charAt(tableOrColumnName.indexOf("_")+1));

        tableOrColumnName = tableOrColumnName.replace("_"+old,old.toUpperCase());
        return dbNameHandle(tableOrColumnName);
    }

    /**
     * 数据库_命名转化为驼峰式命名,首字母大写
     * @param name
     * @return
     */
    public static String initialCaps(String name){
        String temp = dbNameHandle(name);
        return String.valueOf(temp.charAt(0)).toUpperCase()+temp.substring(1,temp.length());
    }

    /**
     * 数据库字段类型转换
     * @return
     */
    public static String type2Property(String type){
        if(type.matches("VARCHAR|CHAR|TEXT")){
            return "String";
        }
        if(type.indexOf("BLOB")!=-1){
            return "byte[]";
        }
        if(type.matches("DATE|TIME|DATETIME|TIMESTAMP|YEAR")){
            return "Date";
        }
        if(type.matches("INT|TINYINT|SMALLINT|BIGINT|DECIMAL")){
            return "Integer";
        }
        return type;
    }
}

元数据构建需要的数据库信息对象

由于方便调用做成工具类,直接使用的原生jdbc获取元数据信息:
1、获取所有表名:

rs = metaData.getTables(null, null, "%", new String[]{"TABLE"});

2、获取字段信息:

rs = metaData.getColumns(null, "%", tableName, "%");

3、获取主键字段名:

pks = metaData.getPrimaryKeys(config.getDbName(), "%", tableName);
package com.lin.util;

import java.sql.*;
import java.util.*;

public class DBUtil {

    /**
     * 获取所有表名
     *
     * @param config
     */
    public static List<String> getTableNames(Config config) {
        Connection cnn = getConn(config);
        ResultSet rs = null;
        List<String> tableNames = new ArrayList<>();
        try {
            DatabaseMetaData metaData = cnn.getMetaData();
            rs = metaData.getTables(null, null, "%", new String[]{"TABLE"});
            while (rs.next()) {
                String tableName = rs.getString("TABLE_NAME");
                if (tableName.equals("schema_version")) {
                    continue;
                }
                tableNames.add(tableName);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            close(cnn, null, rs);
        }
        return tableNames;
    }

    /**
     * 获取数据库连接
     *
     * @param config
     * @return
     */
    public static Connection getConn(Config config) {
        Connection conn = null;
        try {
            Class.forName(config.getDbDriver());
            conn = DriverManager.getConnection(config.getBdUrl(), config.getDbUserName(), config.getDbPassword());
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return conn;
    }

    /**
     * 获取table元信息
     */
    public static List<TableInfo> getTableInfos(Config config) {

        List<String> tableNamesList = new ArrayList<>();
        if ("*".equals(config.getTableName())) {
            tableNamesList = getTableNames(config);
        } else {
            tableNamesList.addAll(Arrays.asList(config.getTableName().split(",")));
        }
        List<TableInfo> tableInfoList = new ArrayList<>();
        Connection cnn = getConn(config);
        ResultSet rs = null;
        DatabaseMetaData metaData;
        try {
            for (String tableName : tableNamesList) {
                TableInfo tableInfo = new TableInfo();
                List<ColumnInfo> columnInfoList = new ArrayList<>();
                tableInfo.setTableName(StringDBUtil.initialCaps(tableName));
                tableInfo.setOriginTableName(tableName);
                metaData = cnn.getMetaData();
                //获取主键字段名
                ResultSet pks = metaData.getPrimaryKeys(config.getDbName(), "%", tableName);
                String pkName = null;
                while (pks.next()) {
                    pkName = pks.getString("COLUMN_NAME");
                }
                //获取字段信息
                rs = metaData.getColumns(null, "%", tableName, "%");
                while (rs.next()) {
                    ColumnInfo column = new ColumnInfo();
                    String columnName = rs.getString("COLUMN_NAME");
                    column.setColumnName(StringDBUtil.dbNameHandle(columnName));
                    column.setOriginColumnName(columnName);
                    column.setColumnType(StringDBUtil.type2Property(rs.getString("TYPE_NAME")));
                    column.setRemarks(rs.getString("REMARKS"));
                    columnInfoList.add(column);
                    if(columnName.equals(pkName)){
                        tableInfo.setPrimaryKeyColumn(column);
                        if(rs.getString("IS_AUTOINCREMENT").equals("YES")){
                            tableInfo.setAutoIncrement(true);
                        }else{
                            tableInfo.setAutoIncrement(false);}
                    }
                }
                tableInfo.setColumnInfoList(columnInfoList);
                tableInfoList.add(tableInfo);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            close(cnn, null, rs);
        }
        return tableInfoList;
    }

    /**
     * 关闭资源
     */
    public static void close(Connection conn, PreparedStatement ps, ResultSet rs) {
        if (rs != conn) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                if (null != ps) {
                    try {
                        ps.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    } finally {
                        if (null != conn) {
                            try {
                                conn.close();
                            } catch (SQLException e) {
                                System.out.println("数据库连接关闭失败!");
                            }
                        }
                    }
                }
            }
        }
    }
}

构建生成代码的工具类

直接上代码

package com.lin.util;

import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.*;

public class GenerateUtil {

    public static final String  FTL_TEMPLATE_PATH = "/webapp/WEB-INF/ftl";

    public static final String  ROOT_PATH = System.getProperty("user.dir") + "/src/main";

    public static final List<String> FTL_TYPES = new ArrayList<>();

    public static final List<String> PACKAGE_TO__POJO = new ArrayList<>();

    static {
        PACKAGE_TO__POJO.addAll(Arrays.asList(new String[]{"pageDesc","response"}));

        FTL_TYPES.addAll(Arrays.asList(new String[]{"pojo","pageDesc","service","controller","response",
                "serviceImpl","dao","daoImpl","js","jsp"}));
    }

    /**
     * 生成单表的单个模板代码
     */
    public static void generateBase(TableInfo tableInfo,String ftlType){
        Config config = (Config) Xml2ConfigBean.getBean("config.xml");
        Map<String,Object> dataMap = new HashMap<>();
        dataMap.put("config",config);
        dataMap.put("tableInfo",tableInfo);
        Configuration cfg = new Configuration(Configuration.VERSION_2_3_23);
        try {
            cfg.setDirectoryForTemplateLoading(new File(ROOT_PATH + FTL_TEMPLATE_PATH));
            cfg.setObjectWrapper(new DefaultObjectWrapper(Configuration.VERSION_2_3_23));
            Template temp = cfg.getTemplate(ftlType + ".ftl");
            String sufixName = ".java";
            String filePath = ROOT_PATH + "/java/" + (config.getBasePackage()).replace(".",File.separator) + File.separator + (PACKAGE_TO__POJO.contains(ftlType)?"pojo":ftlType);
            if(ftlType.equals("js")){
                sufixName = ".js";
                filePath = ROOT_PATH + "/webapp/assets/" + tableInfo.getTableName() + StringDBUtil.initialCaps(ftlType);
            }
            if(ftlType.equals("jsp")){
                sufixName = ".jsp";
                filePath = ROOT_PATH + "/webapp/WEB-INF/jsp/" + tableInfo.getTableName() + StringDBUtil.initialCaps(ftlType);
            }
            if(!"/".equals(config.getBaseDir())){
                filePath = config.getBaseDir() + File.separator + ftlType;
            }
            String fileName = tableInfo.getTableName()+ StringDBUtil.initialCaps(ftlType) +sufixName;
            if(ftlType.equals("pojo")){
                fileName = tableInfo.getTableName()+ sufixName;
            }
            if(PACKAGE_TO__POJO.contains(ftlType)){
                fileName = StringDBUtil.initialCaps(ftlType) + sufixName;
            }
            File file = new File(filePath);
            if(!file.exists()){
                file.mkdirs();
            }
            File generateFile = new File(filePath + File.separator + fileName);
            FileWriter fw = new FileWriter(generateFile);
            BufferedWriter bw = new BufferedWriter(fw);
            temp.process(dataMap, bw);
            bw.flush();
            fw.close();
            System.out.println("生成  " + fileName  +"   -->   " + generateFile.getCanonicalPath());
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TemplateException e) {
            e.printStackTrace();
        }
    }

    /**
     * 生成配置项表名的一套代码
     */
    public static void generate(Config config){
        if (null == config){
            config = (Config) Xml2ConfigBean.getBean("config.xml");
        }
        List<TableInfo> tableInfoList = DBUtil.getTableInfos(config);
        for (TableInfo tableInfo:tableInfoList) {
           for (String ftlType:FTL_TYPES){
               generateBase(tableInfo,ftlType);
           }
        }
    }
}

好了准备工作已经完成,生成的工类也写完了,那么如何定制需要的代码模板,譬如mybatis的持久层mapper文件,当我需要集成其他持久层框架,也能随时替换,再者加上上文说生成controller访问层、js、静态页面html,varCode实现的json格式响应类、pageDesc分页类、持久层动态sql、自己定义的业务通用方法,等等生成的代码自动放入项目路径(类文件存放于java包路径、js、jsp存放于webapp路径)、编译、执行,直接就能使用的。
从代码可以看出
在这里插入图片描述
(截图亦为freemarker模板的使用——>构建map存放对象信息——>获取模板——>渲染、流输出文件)
上篇http服务端、客户端的简单实现文章也说了,用freemarker模板引擎,个性化实现你的ftl模板文件,有多少需求、生成多少代码,模板编写的通用,那就是一次编写、处处收益!(哈哈,差点携程java的跨平台口号:一次编译,处处运行!)

freemarker简介

语法:类似el表达式
标签以“#”开头,“@”为自定义标签语法
结合模板中使用的列举以下常用标签:

1、${}

取模型中的值,就当el取值表达式一样,“.”和“[]”获取对象属性和集合元素

2、<#if></#if>
<#if columnInfo.remarks??>
    /**
    *columnInfo.remarks
    */
</#if>

pojo.ftl模板中获取数据库字段comment就当作属性的注释,columnInfo.remarks??为true注释显示(??后面解释),支持<#else if><#else>

3、<#list></#list>
<#list tableInfo.columnInfoList as columnInfo>
    public ${columnInfo.columnType} get${columnInfo.columnName?cap_first}() {
    return ${columnInfo.columnName};
    }
</#list>

pojo.ftl模板中定义get方法(定义属性、set方法也是),循环表的所有列
相当于java代码for(Object obj:list)el表达式<c:forEach items="${list}" var="obj">
list循环中提供<#break>结束循环,未提供continue,可结合<#if>实现,获取下标值 as 后的对象+_index

4、<#assign>

声名变量,类似var
来看个包含上面三个标签的综合体

<#assign field_count = "">
    <#list tableInfo.columnInfoList as columnInfo>
        <#if tableInfo.autoIncrement && (columnInfo.columnName!=tableInfo.primaryKeyColumn.columnName)>
            <#assign field_count = field_count + columnInfo?is_last?string("?","?, ")>
        </#if>
    </#list>

daoimpl.ftl代码中声明空字符串拼接新增sql语句,循环遍历所有字段、如果主键自增长,则插入的主键值和占位符?,就少拼接一个(代码中也实现了,非自增长,生成可供使用的序列值)使用中声明两次递归拼接需要的变量值

5、??以及?、!

以上标签已经够用了,功能更强的自定义标签可以实现TemplateDirectiveModel接口,类似于jstl库自定义标签继承的SimpleTagSupport
下面来介绍常用的函数以及上文??以及?、!含义:
1、??是否为null判断,freemarker取值本身无法识别null(报错)
2、?引用函数
比如:<#assign db_fields = db_fields + columnInfo.originColumnName + columnInfo?is_last?string("",", ")>集合下表是否最后一个

${tableInfo.tableName?uncap_first}首字母大写
${tableInfo.primaryKeyColumn.columnName?cap_first}首字母小写

?后面即是引用的函数名,columnInfo?is_last?string("",", ")第二个?是三目运算符标志,后面不支持:来表示是否的取值,而是用string函数分别取括号前后两个参数
3、!后面接如果为空的默认值 相当于Oracle的decode、nvl

6、运算符

+的字符串连接,数学运算符(求余、取模等)、逻辑运算符、比较运算符(><相当于gt lt,==相当于e)和其他语法大体适用

构建ftl模板文件

有了freemarker模板引擎的简单了解,生成我们需要的模板文件就不是难事了,
存放于WEB-INF下的模板(路径可配)
在这里插入图片描述
dao、service大体没啥难度,
持久层我实现的是jdbc,支持日常curd方法、按字段联合查询、模糊查询、分页查询、动态sql;
controller层自定义response响应对象、继承swagger2 在线api文档(方便调试接口)、字段唯一性校验
代码较多,贴下controller模板:

@Controller
@Api(value = "${tableInfo.tableName} Controller",tags={"${tableInfo.tableName}操作接口Api"})
@RequestMapping("/${tableInfo.tableName?uncap_first}")
public class ${tableInfo.tableName}Controller {

    @Autowired
    private ${tableInfo.tableName}Service ${tableInfo.tableName}Service;

    public static final List<String> UNIQUE_FIELDS = new ArrayList<>();

    static{
        UNIQUE_FIELDS.addAll(Arrays.asList(new String[]{}));//数组内添加需要唯一校验的字段
    }

    @RequestMapping(value="/listPage",method = RequestMethod.GET)
    @ResponseBody
    @ApiOperation(value="获取${tableInfo.tableName?uncap_first}列表",notes="响应成功:0,失败:-1")
    @ApiImplicitParam(name = "pageDesc", value = "分页对象", required = true, dataType = "PageDesc")
    public Response listAll(PageDesc pageDesc){
        List<${tableInfo.tableName}> ${tableInfo.tableName?uncap_first}List = ${tableInfo.tableName}Service.listAll(pageDesc);
        return Response.ok(${tableInfo.tableName?uncap_first}List);
    }

    @RequestMapping(value="/update",method = RequestMethod.POST)
    @ResponseBody
    @ApiOperation(value="新增、更新对象",notes="响应成功:0,失败:-1")
    @ApiImplicitParam(name = "${tableInfo.tableName?uncap_first}", value = "${tableInfo.tableName?uncap_first}对象", required = true, dataType = "${tableInfo.tableName}")
    public Response update${tableInfo.tableName}(${tableInfo.tableName} ${tableInfo.tableName?uncap_first}){
        ${tableInfo.primaryKeyColumn.columnType} ${tableInfo.primaryKeyColumn.columnName} = ${tableInfo.tableName?uncap_first}.get${tableInfo.primaryKeyColumn.columnName?cap_first}();
        //更新
        if(null != ${tableInfo.primaryKeyColumn.columnName}){
            if(!UNIQUE_FIELDS.isEmpty()){
                for(String field:UNIQUE_FIELDS){
                    Map<String,Object> map = new HashMap<>();
                    map.put(field,${tableInfo.tableName?uncap_first}.get(field));
                    List<${tableInfo.tableName}> ${tableInfo.tableName?uncap_first}List = ${tableInfo.tableName}Service.get${tableInfo.tableName}List(map);
                    if(null == ${tableInfo.tableName?uncap_first}List||${tableInfo.tableName?uncap_first}List.get(0).get${tableInfo.primaryKeyColumn.columnName?cap_first}().equals(${tableInfo.primaryKeyColumn.columnName})){
                        ${tableInfo.tableName}Service.update${tableInfo.tableName}(${tableInfo.tableName?uncap_first},"UPDATE");
                        return Response.ok();
                    }else{
                        return Response.error(field+":"+${tableInfo.tableName?uncap_first}.get(field)+"已存在!");
                    }
                }
            }
        ${tableInfo.tableName}Service.update${tableInfo.tableName}(${tableInfo.tableName?uncap_first},"UPDATE");
        return Response.ok();
        //新增
        }else{
            if(!UNIQUE_FIELDS.isEmpty()){
                for(String field:UNIQUE_FIELDS){
                    Map<String,Object> map = new HashMap<>();
                    map.put(field,${tableInfo.tableName?uncap_first}.get(field));
                    List<${tableInfo.tableName}> ${tableInfo.tableName?uncap_first}List = ${tableInfo.tableName}Service.get${tableInfo.tableName}List(map);
                    if(null == ${tableInfo.tableName?uncap_first}List){
                        ${tableInfo.tableName}Service.update${tableInfo.tableName}(${tableInfo.tableName?uncap_first},"ADD");
                        return Response.ok();
                    }else{
                        return Response.error(field+":"+${tableInfo.tableName?uncap_first}.get(field)+"已存在!");
                    }
                 }
            }
            ${tableInfo.tableName}Service.update${tableInfo.tableName}(${tableInfo.tableName?uncap_first},"ADD");
            return Response.ok();
        }
    }

    @RequestMapping(value="/{${tableInfo.primaryKeyColumn.columnName}}",method = RequestMethod.GET)
    @ResponseBody
    @ApiOperation(value="按主键${tableInfo.primaryKeyColumn.columnName}查询${tableInfo.tableName?uncap_first}",notes="响应成功:0,失败:-1")
    @ApiImplicitParam(name = "${tableInfo.primaryKeyColumn.columnName}", value = "${tableInfo.primaryKeyColumn.columnName}", required = true, dataType = "${tableInfo.primaryKeyColumn.columnType}")
    public Response get${tableInfo.tableName}By${tableInfo.primaryKeyColumn.columnName?cap_first}(@PathVariable ${tableInfo.primaryKeyColumn.columnType} ${tableInfo.primaryKeyColumn.columnName}){
        ${tableInfo.tableName} ${tableInfo.tableName?uncap_first} = ${tableInfo.tableName}Service.get${tableInfo.tableName}By${tableInfo.primaryKeyColumn.columnName?cap_first}(${tableInfo.primaryKeyColumn.columnName});
        return Response.ok(${tableInfo.tableName?uncap_first});
    }

    @RequestMapping(value="/delete/{${tableInfo.primaryKeyColumn.columnName}}",method = RequestMethod.GET)
    @ResponseBody
    @ApiOperation(value="根据${tableInfo.primaryKeyColumn.columnName}删除${tableInfo.tableName?uncap_first}",notes="响应成功:0,失败:-1")
    @ApiImplicitParam(name = "${tableInfo.primaryKeyColumn.columnName}", value = "${tableInfo.primaryKeyColumn.columnName}", required = true, dataType = "${tableInfo.primaryKeyColumn.columnType}")
    public Response delete${tableInfo.tableName}By${tableInfo.primaryKeyColumn.columnName?cap_first}(@PathVariable ${tableInfo.primaryKeyColumn.columnType} ${tableInfo.primaryKeyColumn.columnName}){
        ${tableInfo.tableName} ${tableInfo.tableName?uncap_first} = ${tableInfo.tableName}Service.delete${tableInfo.tableName}By${tableInfo.primaryKeyColumn.columnName?cap_first}(${tableInfo.primaryKeyColumn.columnName});
        return Response.ok(${tableInfo.tableName?uncap_first});
    }

    @RequestMapping(value="/list",method = RequestMethod.POST)
    @ResponseBody
    @ApiOperation(value="按条件查询${tableInfo.tableName?uncap_first}集合",notes="响应成功:0,失败:-1")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "map", value = "key值${tableInfo.tableName?uncap_first}属性", required = true, dataType = "Map<String,Object>"),
        @ApiImplicitParam(name = "pageDesc", value = "pageDesc", required = false, dataType = "PageDesc")
    })
    public Response get${tableInfo.tableName}List(Map<String,Object> map,PageDesc pageDesc){
        List<${tableInfo.tableName}> ${tableInfo.tableName?uncap_first}List = ${tableInfo.tableName}Service.get${tableInfo.tableName}List(map,pageDesc);
        return Response.ok(${tableInfo.tableName?uncap_first}List);
    }

    @RequestMapping(value="/like",method = RequestMethod.POST)
    @ResponseBody
    @ApiOperation(value="按条件模糊查询${tableInfo.tableName?uncap_first}集合",notes="响应成功:0,失败:-1")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "map", value = "key值${tableInfo.tableName?uncap_first}属性", required = true, dataType = "Map<String,Object>"),
        @ApiImplicitParam(name = "pageDesc", value = "pageDesc", required = false, dataType = "PageDesc")
    })
    public Response getListLike(Map<String,Object> map,PageDesc pageDesc){
        List<${tableInfo.tableName}> ${tableInfo.tableName?uncap_first}List = ${tableInfo.tableName}Service.getListLike(map,pageDesc);
        return Response.ok(${tableInfo.tableName?uncap_first}List);
    }
}

看下测试效果:
配置如下
在这里插入图片描述
主程序入口:(config传null,表示解析本地的xml文件,后面改为页面表单配置,提交传入config配置参数)

package com.lin;


import com.lin.util.GenerateUtil;
import org.springframework.beans.factory.annotation.Autowired;

public class TestMain {
    @Autowired
    public static void main(String[] args) {
        GenerateUtil.generate(null);
    }
}

在这里插入图片描述
打开一个controller和daoImpl看看效果吧:
在这里插入图片描述
UserController

@Controller
@Api(value = "User Controller",tags={"User操作接口Api"})
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService UserService;

    public static final List<String> UNIQUE_FIELDS = new ArrayList<>();

    static{
        UNIQUE_FIELDS.addAll(Arrays.asList(new String[]{}));//数组内添加需要唯一校验的字段
    }

    @RequestMapping(value="/listPage",method = RequestMethod.GET)
    @ResponseBody
    @ApiOperation(value="获取user列表",notes="响应成功:0,失败:-1")
    @ApiImplicitParam(name = "pageDesc", value = "分页对象", required = true, dataType = "PageDesc")
    public Response listAll(PageDesc pageDesc){
        List<User> userList = UserService.listAll(pageDesc);
        return Response.ok(userList);
    }

    @RequestMapping(value="/update",method = RequestMethod.POST)
    @ResponseBody
    @ApiOperation(value="新增、更新对象",notes="响应成功:0,失败:-1")
    @ApiImplicitParam(name = "user", value = "user对象", required = true, dataType = "User")
    public Response updateUser(User user){
        Integer id = user.getId();
        //更新
        if(null != id){
            if(!UNIQUE_FIELDS.isEmpty()){
                for(String field:UNIQUE_FIELDS){
                    Map<String,Object> map = new HashMap<>();
                    map.put(field,user.get(field));
                    List<User> userList = UserService.getUserList(map);
                    if(null == userList||userList.get(0).getId().equals(id)){
                        UserService.updateUser(user,"UPDATE");
                        return Response.ok();
                    }else{
                        return Response.error(field+":"+user.get(field)+"已存在!");
                    }
                }
            }
        UserService.updateUser(user,"UPDATE");
        return Response.ok();
        //新增
        }else{
            if(!UNIQUE_FIELDS.isEmpty()){
                for(String field:UNIQUE_FIELDS){
                    Map<String,Object> map = new HashMap<>();
                    map.put(field,user.get(field));
                    List<User> userList = UserService.getUserList(map);
                    if(null == userList){
                        UserService.updateUser(user,"ADD");
                        return Response.ok();
                    }else{
                        return Response.error(field+":"+user.get(field)+"已存在!");
                    }
                 }
            }
            UserService.updateUser(user,"ADD");
            return Response.ok();
        }
    }

    @RequestMapping(value="/{id}",method = RequestMethod.GET)
    @ResponseBody
    @ApiOperation(value="按主键id查询user",notes="响应成功:0,失败:-1")
    @ApiImplicitParam(name = "id", value = "id", required = true, dataType = "Integer")
    public Response getUserById(@PathVariable Integer id){
        User user = UserService.getUserById(id);
        return Response.ok(user);
    }

    @RequestMapping(value="/delete/{id}",method = RequestMethod.GET)
    @ResponseBody
    @ApiOperation(value="根据id删除user",notes="响应成功:0,失败:-1")
    @ApiImplicitParam(name = "id", value = "id", required = true, dataType = "Integer")
    public Response deleteUserById(@PathVariable Integer id){
        User user = UserService.deleteUserById(id);
        return Response.ok(user);
    }

    @RequestMapping(value="/list",method = RequestMethod.POST)
    @ResponseBody
    @ApiOperation(value="按条件查询user集合",notes="响应成功:0,失败:-1")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "map", value = "key值user属性", required = true, dataType = "Map<String,Object>"),
        @ApiImplicitParam(name = "pageDesc", value = "pageDesc", required = false, dataType = "PageDesc")
    })
    public Response getUserList(Map<String,Object> map,PageDesc pageDesc){
        List<User> userList = UserService.getUserList(map,pageDesc);
        return Response.ok(userList);
    }

    @RequestMapping(value="/like",method = RequestMethod.POST)
    @ResponseBody
    @ApiOperation(value="按条件模糊查询user集合",notes="响应成功:0,失败:-1")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "map", value = "key值user属性", required = true, dataType = "Map<String,Object>"),
        @ApiImplicitParam(name = "pageDesc", value = "pageDesc", required = false, dataType = "PageDesc")
    })
    public Response getListLike(Map<String,Object> map,PageDesc pageDesc){
        List<User> userList = UserService.getListLike(map,pageDesc);
        return Response.ok(userList);
    }
}

UserDaoImpl

@Repository
public class UserDaoImpl implements UserDao {


    private static final Map<String,Object> FIELD_MAP = new HashMap<>();

    static{
        FIELD_MAP.put("id","id");
        FIELD_MAP.put("userName","userName");
        FIELD_MAP.put("password","password");
        FIELD_MAP.put("sex","sex");
    }

    @Autowired
    private JdbcTemplate jdbcTemplate;

    /**
    * @param pageDesc 分页对象
    * @return 获取user列表
    */
    @Override
    public List<User> listAll(PageDesc pageDesc){
        return getUserList(null,pageDesc);
    }

    /**
    * @param user 新增(支持auto_increment插值)、更新对象
    * @param type 操作类型
    */
    @Override
    public void updateUser(User user,String type){

        Integer id = user.getId();
        String sql = "INSERT INTO f_user(userName, password, sex) values(?, ?, ?)";
        //更新
        if(type.equals("UPDATE")){
            deleteUserById(id);
            jdbcTemplate.update(sql, new Object[]{user.getUserName(), user.getPassword(), user.getSex()});
        //新增
        }else{
            jdbcTemplate.update(sql, new Object[]{user.getUserName(), user.getPassword(), user.getSex()});
        }
    }

    /**
    * @param id
    * @return 按主键id查询user
    */
    @Override
    public User getUserById(Integer id){

        String sql = "SELECT id, userName, password, sex FROM f_user WHERE id = ?";
        RowMapper<User> rowMapper = new BeanPropertyRowMapper(User.class);
        return jdbcTemplate.queryForObject(sql, rowMapper, id);
    }

    /**
    * @param id
    * @return 删除的user对象
    */
    @Override
    public User deleteUserById(Integer id){

        User user = getUserById(id);
        String sql = "DELETE FROM f_user WHERE id = ?";
        jdbcTemplate.update(sql, id);
        return user;
    }

    /**
    * @param map key只能是FIELD_MAP中的值,即pojo属性名
    * @param pageDesc 分页对象
    * @return 按条件查询的user集合
    */
    @Override
    public List<User> getUserList(Map<String,Object> map,PageDesc pageDesc){

        StringBuilder sql = new StringBuilder("SELECT id, userName, password, sex FROM f_user WHERE 1=1 ");
        if(null != map){
            for (String param:map.keySet()){
                sql.append(" and " + FIELD_MAP.get(param) + " = ? ");
            }
        }
        if(null != pageDesc){
            sql.append(" LIMIT " + pageDesc.getRowStart() + "," + pageDesc.getRowEnd());
        }
        RowMapper<User> rowMapper = new BeanPropertyRowMapper(User.class);
        return jdbcTemplate.query(sql.toString(), map.values().toArray(),rowMapper);
    }

    /**
    * @param map key只能是FIELD_MAP中的值,即pojo属性名
    * @return 按条件查询的user集合
    */
    @Override
    public List<User> getUserList(Map<String,Object> map){
        return getUserList(map,null);
    }

    /**
    * @param map key只能是FIELD_MAP中的值,即pojo属性名
    * @param pageDesc 分页对象
    * @return 模糊查询user集合
    */
    @Override
    public List<User> getListLike(Map<String,Object> map,PageDesc pageDesc){

        StringBuilder sql = new StringBuilder("SELECT id, userName, password, sex FROM f_user WHERE 1=1 ");
        if(null != map){
            for (String param:map.keySet()){
                sql.append(" and " + FIELD_MAP.get(param) + " LIKE CONCAT('%',?,'%') ");
            }
        }
        if(null != pageDesc){
            sql.append(" LIMIT " + pageDesc.getRowStart() + "," + pageDesc.getRowEnd());
        }
        RowMapper<User> rowMapper = new BeanPropertyRowMapper(User.class);
        return jdbcTemplate.query(sql.toString(), map.values().toArray(),rowMapper);
    }

    /**
    * @param map key只能是FIELD_MAP中的key值,即pojo属性名
    * @return 模糊查询user集合
    */
    @Override
    public List<User> getListLike(Map<String,Object> map){
        return getListLike(map,null);
    }

}

启动项目(本身就是web项目),swagger2界面api:
在这里插入图片描述
测试直接可用
在这里插入图片描述
后期更新完善好(页面配置、mybatis、herbinate多元持久层)提供源码地址,谢谢!。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值