├── .gitignore ├── .travis.yml ├── BuildSrc ├── build.gradle └── src │ └── main │ ├── java │ └── com │ │ └── zjiecode │ │ └── web │ │ └── generator │ │ ├── ConfigExtension.java │ │ ├── GenerateException.java │ │ ├── GenerateTask.java │ │ ├── WebApiCodeGeneratePlugin.java │ │ ├── bean │ │ ├── FieldBean.java │ │ └── FileResBean.java │ │ ├── generate │ │ ├── GenerateBase.java │ │ ├── GenerateBean.java │ │ ├── GenerateController.java │ │ ├── GenerateMapper.java │ │ ├── GenerateService.java │ │ └── GenerateSqlProvider.java │ │ └── utils │ │ ├── FieldTypeUtil.java │ │ ├── FileResList.java │ │ ├── NameUtil.java │ │ └── PathUtil.java │ └── resources │ ├── META-INF │ └── gradle-plugins │ │ └── javaweb-api-generate.properties │ ├── config │ ├── application-dev.properties │ ├── application-prod.properties │ ├── application.properties │ └── banner.txt │ └── java │ ├── AppWebMvcConfigurer.java │ ├── JavaWebApplication.java │ ├── Pagination.java │ ├── exception │ ├── AppException.java │ └── BizException.java │ └── result │ ├── Result.java │ └── ResultCode.java ├── LICENSE ├── TestGradlePlugin └── build.gradle ├── build.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── publish.sh ├── readme.md ├── settings.gradle └── setup ├── setup.sh └── template.zip /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /build/ 3 | /BuildSrc/out/ 4 | /BuildSrc/build/ 5 | /TestGradlePlugin/out/ 6 | /TestGradlePlugin/build/ 7 | /TestGradlePlugin/src/ 8 | /TestGradlePlugin/src-bak/ 9 | !gradle/wrapper/gradle-wrapper.jar 10 | repo 11 | .DS_Store 12 | ### STS ### 13 | .apt_generated 14 | .classpath 15 | .factorypath 16 | .project 17 | .settings 18 | .springBeans 19 | .sts4-cache 20 | 21 | ### IntelliJ IDEA ### 22 | .idea 23 | *.iws 24 | *.iml 25 | *.ipr 26 | /out/ 27 | 28 | ### NetBeans ### 29 | /nbproject/private/ 30 | /build/ 31 | /nbbuild/ 32 | /dist/ 33 | /nbdist/ 34 | /.nb-gradle/ -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | install: ./gradlew clean 3 | script: ./gradlew :BuildSrc:assemble -------------------------------------------------------------------------------- /BuildSrc/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java-gradle-plugin' 2 | apply plugin: 'com.novoda.bintray-release' //用户发布到bintray 3 | apply plugin: 'maven'//maven插件,用于发布到本地仓库调试 4 | 5 | //版本信息 6 | def version="0.0.14" 7 | buildscript { 8 | repositories { 9 | jcenter() 10 | mavenCentral() 11 | } 12 | dependencies { 13 | classpath "com.novoda:bintray-release:0.8.1" 14 | } 15 | } 16 | 17 | //用于发布到本地仓库调试的配置 18 | uploadArchives { 19 | repositories { 20 | mavenDeployer { 21 | repository(url: uri('../repo')) 22 | pom.groupId = 'com.zjiecode' // 组名 23 | pom.artifactId = 'javaweb-api-generate' // 插件名 24 | pom.version = "${version}" // 版本号 25 | } 26 | } 27 | } 28 | 29 | repositories { 30 | jcenter() 31 | mavenCentral() 32 | } 33 | dependencies { 34 | compile 'mysql:mysql-connector-java:5.1.44'//连接数据库 35 | compile 'com.squareup:javapoet:1.10.0'//生成java源文件 36 | } 37 | 38 | //发布bintray配置 39 | publish { 40 | userOrg = 'zjiecode' 41 | groupId = 'com.zjiecode' 42 | artifactId = 'javaweb-api-generate' 43 | publishVersion = "${version}" 44 | desc = '一个可以根据数据库结构,快速生成基于spring boot常用API接口的gradle插件。生成的工程是idea+gradle+springboot+mysql+validation-api框架结构的工程。' 45 | website = 'https://github.com/zjiecode/javaweb-api-generate' 46 | licences = ['Apache-2.0'] 47 | } 48 | -------------------------------------------------------------------------------- /BuildSrc/src/main/java/com/zjiecode/web/generator/ConfigExtension.java: -------------------------------------------------------------------------------- 1 | package com.zjiecode.web.generator;//package com.zjiecode.web.generator 2 | 3 | /** 4 | * 生成代码的配置 5 | */ 6 | class ConfigExtension { 7 | 8 | private String dbHost = "127.0.0.1"; 9 | private String dbPort = "3306"; 10 | private String dbName; 11 | private String dbUser = "root"; 12 | private String dbPassword; 13 | private String dbDriver; 14 | private String basePackage; 15 | 16 | public ConfigExtension() { 17 | } 18 | 19 | public ConfigExtension(String dbHost, String dbPort, String dbName, String dbUser, String dbPassword, String dbDriver, String basePackage) { 20 | this.dbHost = dbHost; 21 | this.dbPort = dbPort; 22 | this.dbName = dbName; 23 | this.dbUser = dbUser; 24 | this.dbPassword = dbPassword; 25 | this.dbDriver = dbDriver; 26 | this.basePackage = basePackage; 27 | } 28 | 29 | public String getBasePackage() { 30 | return basePackage; 31 | } 32 | 33 | public void setBasePackage(String basePackage) { 34 | this.basePackage = basePackage; 35 | } 36 | 37 | public String getDbHost() { 38 | return dbHost; 39 | } 40 | 41 | public void setDbHost(String dbHost) { 42 | this.dbHost = dbHost; 43 | } 44 | 45 | public String getDbPort() { 46 | return dbPort; 47 | } 48 | 49 | public void setDbPort(String dbPort) { 50 | this.dbPort = dbPort; 51 | } 52 | 53 | public String getDbName() { 54 | return dbName; 55 | } 56 | 57 | public void setDbName(String dbName) { 58 | this.dbName = dbName; 59 | } 60 | 61 | public String getDbUser() { 62 | return dbUser; 63 | } 64 | 65 | public void setDbUser(String dbUser) { 66 | this.dbUser = dbUser; 67 | } 68 | 69 | public String getDbPassword() { 70 | return dbPassword; 71 | } 72 | 73 | public void setDbPassword(String dbPassword) { 74 | this.dbPassword = dbPassword; 75 | } 76 | 77 | public String getDbDriver() { 78 | return dbDriver; 79 | } 80 | 81 | public void setDbDriver(String dbDriver) { 82 | this.dbDriver = dbDriver; 83 | } 84 | } -------------------------------------------------------------------------------- /BuildSrc/src/main/java/com/zjiecode/web/generator/GenerateException.java: -------------------------------------------------------------------------------- 1 | package com.zjiecode.web.generator; 2 | 3 | /** 4 | * 生成代码的时候,发生错误 5 | */ 6 | public class GenerateException extends RuntimeException { 7 | public GenerateException(String message) { 8 | super(message); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /BuildSrc/src/main/java/com/zjiecode/web/generator/GenerateTask.java: -------------------------------------------------------------------------------- 1 | package com.zjiecode.web.generator; 2 | 3 | import com.squareup.javapoet.ClassName; 4 | import com.zjiecode.web.generator.bean.FieldBean; 5 | import com.zjiecode.web.generator.bean.FileResBean; 6 | import com.zjiecode.web.generator.generate.*; 7 | import com.zjiecode.web.generator.utils.FileResList; 8 | import com.zjiecode.web.generator.utils.PathUtil; 9 | import org.gradle.api.DefaultTask; 10 | import org.gradle.api.tasks.Input; 11 | import org.gradle.api.tasks.TaskAction; 12 | 13 | import java.io.*; 14 | import java.sql.*; 15 | import java.util.ArrayList; 16 | import java.util.List; 17 | 18 | public class GenerateTask extends DefaultTask { 19 | @Input 20 | private ConfigExtension config; 21 | private Connection con; 22 | 23 | public ConfigExtension getConfig() { 24 | return config; 25 | } 26 | 27 | public void setConfig(ConfigExtension config) { 28 | this.config = config; 29 | } 30 | 31 | @TaskAction 32 | private void action() { 33 | try { 34 | Class.forName(config.getDbDriver()); 35 | String url = String.format("jdbc:mysql://%s:%s/%s?useUnicode=true&characterEncoding=utf8&useSSL=false", config.getDbHost(), config.getDbPort(), config.getDbName()); 36 | con = DriverManager.getConnection(url, config.getDbUser(), config.getDbPassword()); 37 | if (con.isClosed()) { 38 | throw new GenerateException("连接数据库失败, 请检查连接"); 39 | } else { 40 | System.out.println("连接数据库成功"); 41 | getTable(); 42 | } 43 | } catch (Exception e) { 44 | e.printStackTrace(); 45 | throw new GenerateException("生成代码失败"); 46 | } 47 | } 48 | 49 | //查询数据库存在的表 50 | private void getTable() throws SQLException { 51 | String sql = "select table_name from information_schema.tables where table_schema='" + config.getDbName() + "' and table_type ='BASE TABLE'"; 52 | PreparedStatement ps = con.prepareStatement(sql); 53 | //3.ResultSet类,用来存放获取的结果集!! 54 | ResultSet rs = ps.executeQuery(); 55 | while (rs.next()) { 56 | String table = rs.getString("table_name"); 57 | getTableDetail(table); 58 | } 59 | generateFixFile(); 60 | } 61 | 62 | //获取表结构 63 | private void getTableDetail(String table) throws SQLException { 64 | System.out.println("正在处理表:" + table); 65 | String sql = "select column_name as col, column_comment as comment,IS_NULLABLE as canNull,COLUMN_KEY,EXTRA,DATA_TYPE as type,NUMERIC_PRECISION as length from information_schema.columns where table_schema ='" + config.getDbName() + "' and table_name = '" + table + "' ORDER by ORDINAL_POSITION ASC"; 66 | PreparedStatement ps = con.prepareStatement(sql); 67 | ResultSet rs = ps.executeQuery(); 68 | List fields = new ArrayList<>(); 69 | while (rs.next()) { 70 | String col = rs.getString("col"); 71 | String comment = rs.getString("comment"); 72 | String canNull = rs.getString("canNull"); 73 | String columnKey = rs.getString("COLUMN_KEY"); 74 | String extra = rs.getString("EXTRA"); 75 | String type = rs.getString("type"); 76 | int length = rs.getInt("length"); 77 | fields.add(new FieldBean(col, comment, type, length, "YES".equalsIgnoreCase(canNull), "PRI".equalsIgnoreCase(columnKey), "auto_increment".equalsIgnoreCase(extra))); 78 | } 79 | // 生成的文件,放在biz包里面 80 | generate(table, fields, config.getBasePackage()); 81 | } 82 | 83 | //生成代码文件 84 | private void generate(String table, List fields, String srcPackage) { 85 | 86 | //生成bean 87 | GenerateBean generateBean = new GenerateBean(table, fields, srcPackage); 88 | generateBean.generate(); 89 | ClassName beanClassName = generateBean.out(); 90 | //生成sqlProvider 因为update方法,使用了sql工厂,所以,需要先生成一个sqlProvider 91 | GenerateSqlProvider generateSqlProvider = new GenerateSqlProvider(beanClassName, table, fields, srcPackage); 92 | generateSqlProvider.generate(); 93 | ClassName sqlProviderClassName = generateSqlProvider.out(); 94 | //生成mapper 95 | GenerateMapper generateMapper = new GenerateMapper(beanClassName, table, fields, srcPackage); 96 | generateMapper.setSqlProviderClassName(sqlProviderClassName); 97 | generateMapper.generate(); 98 | ClassName mapperClassName = generateMapper.out(); 99 | //生成service 100 | GenerateService generateService = new GenerateService(beanClassName, table, fields, srcPackage); 101 | generateService.setMapperClassName(mapperClassName); 102 | generateService.generate(); 103 | ClassName serviceClassName = generateService.out(); 104 | //生成controller 105 | GenerateController generateController = new GenerateController(beanClassName, table, fields, srcPackage); 106 | generateController.setServiceClassName(serviceClassName); 107 | generateController.generate(); 108 | generateController.out(); 109 | 110 | } 111 | 112 | 113 | /** 114 | * 生成固定的文件 115 | */ 116 | private void generateFixFile() { 117 | //拷贝java文件 118 | List javaList = FileResList.getInstance().getJavaList(); 119 | javaList.stream().forEach(file -> { 120 | try { 121 | //根据具体的配置生成输出路径 122 | copyFile(file.getInUrl(), 123 | PathUtil.SRC_ROOT_DIR + File.separator + PathUtil.package2Path(config.getBasePackage()) + File.separator + file.getOutUrl()); 124 | 125 | } catch (IOException e) { 126 | e.printStackTrace(); 127 | System.out.println("拷贝文件[" + file.getOutUrl() + "]出错"); 128 | } 129 | }); 130 | System.out.println("拷贝脚手架java文件完成"); 131 | //拷贝资源文件 132 | List resList = FileResList.getInstance().getResList(); 133 | 134 | resList.stream().forEach(file -> { 135 | try { 136 | //根据具体的配置生成输出路径 137 | copyFile(file.getInUrl(), 138 | PathUtil.RES_ROOT_DIR + File.separator + file.getOutUrl()); 139 | } catch (IOException e) { 140 | e.printStackTrace(); 141 | System.out.println("拷贝文件[" + file.getOutUrl() + "]出错"); 142 | } 143 | }); 144 | System.out.println("拷贝基础配置文件完成"); 145 | //修改数据库配置 146 | resList.stream().forEach(file -> { 147 | try { 148 | if (file.getInUrl().endsWith("-dev.properties")) { 149 | //通过流读取数据库配置文件 150 | String filePath = PathUtil.RES_ROOT_DIR + File.separator + file.getOutUrl(); 151 | File dbFile = new File(filePath); 152 | FileInputStream inputStream = new FileInputStream(dbFile); 153 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 154 | byte[] buffer = new byte[1024]; 155 | int len = 0; 156 | while ((len = inputStream.read(buffer)) != -1) { 157 | out.write(buffer, 0, len); 158 | } 159 | inputStream.close(); 160 | //替换为正确的数据库配置 161 | String dbConfig = new String(out.toByteArray()); 162 | dbConfig = dbConfig.replace("${host}", config.getDbHost()); 163 | dbConfig = dbConfig.replace("${port}", config.getDbPort()); 164 | dbConfig = dbConfig.replace("${dbName}", config.getDbName()); 165 | dbConfig = dbConfig.replace("${user}", config.getDbUser()); 166 | dbConfig = dbConfig.replace("${pwd}", config.getDbPassword()); 167 | //把数据库配置写到文件里面 168 | dbFile.delete(); 169 | dbFile.createNewFile(); 170 | FileOutputStream dbFileOut = new FileOutputStream(dbFile); 171 | dbFileOut.write(dbConfig.getBytes()); 172 | dbFileOut.close(); 173 | } 174 | } catch (IOException e) { 175 | e.printStackTrace(); 176 | System.out.println("修改开发环境配置文件[" + file.getOutUrl() + "]出错"); 177 | } 178 | }); 179 | 180 | 181 | } 182 | 183 | /** 184 | * 复制文件 185 | */ 186 | private void copyFile(String in, String out) throws IOException { 187 | System.out.println("拷贝文件:" + out); 188 | File file = new File(out); 189 | if (!file.getParentFile().exists()) { 190 | file.getParentFile().mkdirs(); 191 | } 192 | InputStream inputStream = this.getClass().getResourceAsStream(in); 193 | ByteArrayOutputStream tempOut = new ByteArrayOutputStream(); 194 | FileOutputStream outputStream = new FileOutputStream(out); 195 | 196 | byte[] buffer = new byte[1024]; 197 | int len = 0; 198 | while ((len = inputStream.read(buffer)) != -1) { 199 | tempOut.write(buffer, 0, len); 200 | } 201 | tempOut.close(); 202 | String source = new String(tempOut.toByteArray()); 203 | if (in.endsWith("java")) { 204 | //java文件需要替换包名 205 | source = source.replace("${package}", config.getBasePackage()); 206 | } 207 | outputStream.write(source.getBytes()); 208 | inputStream.close(); 209 | outputStream.close(); 210 | } 211 | 212 | } 213 | -------------------------------------------------------------------------------- /BuildSrc/src/main/java/com/zjiecode/web/generator/WebApiCodeGeneratePlugin.java: -------------------------------------------------------------------------------- 1 | package com.zjiecode.web.generator; 2 | 3 | import org.gradle.api.Action; 4 | import org.gradle.api.Plugin; 5 | import org.gradle.api.Project; 6 | 7 | public class WebApiCodeGeneratePlugin implements Plugin { 8 | @Override 9 | public void apply(Project project) { 10 | ConfigExtension configExtension = project.getExtensions().create("config", ConfigExtension.class); 11 | GenerateTask generateTask = project.getTasks().create( 12 | "generateCode", GenerateTask.class, 13 | task -> task.setGroup("generate code")); 14 | project.afterEvaluate(new Action() { 15 | @Override 16 | public void execute(Project project) { 17 | generateTask.setConfig(configExtension); 18 | } 19 | }); 20 | 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /BuildSrc/src/main/java/com/zjiecode/web/generator/bean/FieldBean.java: -------------------------------------------------------------------------------- 1 | package com.zjiecode.web.generator.bean; 2 | 3 | /** 4 | * 一个表的每个字段的描述信息 5 | */ 6 | public class FieldBean { 7 | private String name; 8 | private String comment; 9 | private String type; 10 | private int length; 11 | private boolean canNull; 12 | private boolean isPrimary; 13 | private boolean isAutoIncrement; 14 | 15 | public FieldBean(String name, String comment, String type, int length, boolean canNull, boolean isPrimary, boolean isAutoIncrement) { 16 | this.name = name; 17 | this.comment = comment; 18 | this.type = type; 19 | this.length = length; 20 | this.canNull = canNull; 21 | this.isPrimary = isPrimary; 22 | this.isAutoIncrement = isAutoIncrement; 23 | } 24 | 25 | public String getType() { 26 | return type; 27 | } 28 | 29 | public void setType(String type) { 30 | this.type = type; 31 | } 32 | 33 | public int getLength() { 34 | return length; 35 | } 36 | 37 | public void setLength(int length) { 38 | this.length = length; 39 | } 40 | 41 | public String getName() { 42 | return name; 43 | } 44 | 45 | public void setName(String name) { 46 | this.name = name; 47 | } 48 | 49 | public String getComment() { 50 | return comment; 51 | } 52 | 53 | public void setComment(String comment) { 54 | this.comment = comment; 55 | } 56 | 57 | public boolean isCanNull() { 58 | return canNull; 59 | } 60 | 61 | public void setCanNull(boolean canNull) { 62 | this.canNull = canNull; 63 | } 64 | 65 | public boolean isPrimary() { 66 | return isPrimary; 67 | } 68 | 69 | public void setPrimary(boolean primary) { 70 | isPrimary = primary; 71 | } 72 | 73 | public boolean isAutoIncrement() { 74 | return isAutoIncrement; 75 | } 76 | 77 | public void setAutoIncrement(boolean autoIncrement) { 78 | isAutoIncrement = autoIncrement; 79 | } 80 | 81 | public boolean isCommentEmpty() { 82 | return getComment() == null || getComment().length() == 0; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /BuildSrc/src/main/java/com/zjiecode/web/generator/bean/FileResBean.java: -------------------------------------------------------------------------------- 1 | package com.zjiecode.web.generator.bean; 2 | 3 | /** 4 | * 管理固定和资源文件 5 | */ 6 | public class FileResBean { 7 | private String inUrl; 8 | private String outUrl; 9 | 10 | public FileResBean(String inUrl, String outUrl) { 11 | this.inUrl = inUrl; 12 | this.outUrl = outUrl; 13 | } 14 | 15 | public String getInUrl() { 16 | return inUrl; 17 | } 18 | 19 | public void setInUrl(String inUrl) { 20 | this.inUrl = inUrl; 21 | } 22 | 23 | public String getOutUrl() { 24 | return outUrl; 25 | } 26 | 27 | public void setOutUrl(String outUrl) { 28 | this.outUrl = outUrl; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /BuildSrc/src/main/java/com/zjiecode/web/generator/generate/GenerateBase.java: -------------------------------------------------------------------------------- 1 | package com.zjiecode.web.generator.generate; 2 | 3 | import com.squareup.javapoet.ClassName; 4 | import com.squareup.javapoet.JavaFile; 5 | import com.squareup.javapoet.TypeSpec; 6 | import com.zjiecode.web.generator.GenerateException; 7 | import com.zjiecode.web.generator.bean.FieldBean; 8 | import com.zjiecode.web.generator.utils.PathUtil; 9 | 10 | import java.io.File; 11 | import java.util.List; 12 | 13 | /** 14 | * 生成的基类 15 | */ 16 | public class GenerateBase { 17 | private static final String BIZ_PACKAGE_NAME = ".biz"; 18 | protected TypeSpec.Builder classBuilder; 19 | protected ClassName beanClassName; //依赖一个生成的类 20 | protected String table;//表名 21 | protected String srcPackage;//生成文件的包名 22 | protected String basePackage;//基础的包名 23 | protected String type;//生成文件类型 Bean Mapper Controller等 24 | protected List fields;//表的字段 25 | 26 | /** 27 | * 生成实体类,所以没有实体类类名 28 | */ 29 | public GenerateBase(String table, List fields, String basePackage, TypeSpec.Builder classBuilder, String type) { 30 | this.table = table; 31 | this.basePackage = basePackage; 32 | this.srcPackage = basePackage + BIZ_PACKAGE_NAME + "." + table; 33 | this.fields = fields; 34 | this.classBuilder = classBuilder; 35 | this.type = type; 36 | } 37 | 38 | /** 39 | * 生成初开实体类其他的类,都需要用到实体类的类名 40 | */ 41 | public GenerateBase(ClassName beanClassName, String table, List fields, String basePackage, TypeSpec.Builder classBuilder, String type) { 42 | this.beanClassName = beanClassName; 43 | this.table = table; 44 | this.basePackage = basePackage; 45 | this.srcPackage = basePackage + ".biz." + table; 46 | this.fields = fields; 47 | this.classBuilder = classBuilder; 48 | this.type = type; 49 | } 50 | 51 | //输出文件,并且返回完整的生成的类 52 | public ClassName out() { 53 | //判断文件夹不存在,就先生成项目文件夹 54 | File packageDir = new File(PathUtil.SRC_ROOT_DIR, PathUtil.package2Path(srcPackage)); 55 | if (!packageDir.exists()) { 56 | packageDir.mkdirs(); 57 | } 58 | JavaFile javaFile = JavaFile.builder(srcPackage, classBuilder.build()).build(); 59 | try { 60 | javaFile.writeTo(PathUtil.SRC_ROOT_DIR); 61 | String fullClass = javaFile.toJavaFileObject().getName() 62 | .replace('/', '.') 63 | .replace('\\', '.'); 64 | if (fullClass.endsWith(".java")) { 65 | fullClass = fullClass.substring(0, fullClass.length() - 5); 66 | } 67 | System.out.println("[" + table + "]" + type + "生成成功:" + fullClass); 68 | return ClassName.bestGuess(fullClass); 69 | } catch (Exception e) { 70 | e.printStackTrace(); 71 | throw new GenerateException("[" + table + "]" + type + "生成失败:" + e.getMessage()); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /BuildSrc/src/main/java/com/zjiecode/web/generator/generate/GenerateBean.java: -------------------------------------------------------------------------------- 1 | package com.zjiecode.web.generator.generate; 2 | 3 | import com.squareup.javapoet.*; 4 | import com.zjiecode.web.generator.GenerateException; 5 | import com.zjiecode.web.generator.bean.FieldBean; 6 | import com.zjiecode.web.generator.utils.NameUtil; 7 | import com.zjiecode.web.generator.utils.FieldTypeUtil; 8 | 9 | import javax.lang.model.element.Modifier; 10 | import java.lang.reflect.Type; 11 | import java.util.List; 12 | 13 | /** 14 | * 生成实体类 15 | */ 16 | public class GenerateBean extends GenerateBase { 17 | 18 | public GenerateBean(String table, List fields, String basePackage) { 19 | super(table, fields, basePackage, 20 | TypeSpec.classBuilder(NameUtil.className(table)).addModifiers(Modifier.PUBLIC) 21 | .addAnnotation(AnnotationSpec.builder(ClassName.bestGuess("javax.persistence.Entity")).build()), 22 | "Bean"); 23 | } 24 | 25 | public void generate() { 26 | if (fields == null || fields.isEmpty()) { 27 | throw new GenerateException(table + "表没有字段"); 28 | } 29 | fields.stream().forEach(field -> { 30 | Object type = FieldTypeUtil.getType(field); 31 | FieldSpec.Builder fieldBuilder; 32 | String fieldName = NameUtil.fieldName(field.getName()); 33 | if (type instanceof TypeName) { 34 | fieldBuilder = FieldSpec.builder((TypeName) type, fieldName, Modifier.PRIVATE); 35 | } else if (type instanceof Type) { 36 | fieldBuilder = FieldSpec.builder((Type) type, fieldName, Modifier.PRIVATE); 37 | } else { 38 | throw new GenerateException("不支持的数据类型"); 39 | } 40 | 41 | //ID的注解 42 | if (field.isPrimary()) { 43 | fieldBuilder.addAnnotation(AnnotationSpec.builder(ClassName.bestGuess("javax.persistence.Id")).build()); 44 | } 45 | //自动增长的注解 46 | if (field.isAutoIncrement()) { 47 | AnnotationSpec.Builder AotuIncAnnoBuilder = AnnotationSpec.builder(ClassName.bestGuess("javax.persistence.GeneratedValue")); 48 | AotuIncAnnoBuilder.addMember("strategy", "$T", ClassName.bestGuess("javax.persistence.GenerationType.IDENTITY")); 49 | fieldBuilder.addAnnotation(AotuIncAnnoBuilder.build()); 50 | } 51 | //不能为空的注解 52 | if (!field.isCanNull() && !"id".equals(field.getName())) { 53 | AnnotationSpec.Builder notNullAnnoBuilder = AnnotationSpec.builder(ClassName.bestGuess("javax.validation.constraints.NotNull")); 54 | //如果有注释,就取注释,不然,就取字段名 55 | String name = field.isCommentEmpty() ? field.getName() : field.getComment(); 56 | notNullAnnoBuilder.addMember("message", "\"$L不能为空\"", name); 57 | fieldBuilder.addAnnotation(notNullAnnoBuilder.build()); 58 | } 59 | addField(fieldBuilder.build()); 60 | }); 61 | } 62 | 63 | /** 64 | * 添加一个字段 65 | * 自动添加对应的getter、setter 66 | */ 67 | public GenerateBean addField(FieldSpec fieldSpec) { 68 | classBuilder.addField(fieldSpec); 69 | MethodSpec setter = MethodSpec.methodBuilder("set" + NameUtil.className(fieldSpec.name)) 70 | .returns(TypeName.VOID) 71 | .addModifiers(Modifier.PUBLIC) 72 | .addStatement("this.$L = $L", fieldSpec.name, fieldSpec.name) 73 | .addParameter(ParameterSpec.builder(fieldSpec.type, fieldSpec.name).build()).build(); 74 | classBuilder.addMethod(setter); 75 | MethodSpec getter = MethodSpec.methodBuilder("get" + NameUtil.className(fieldSpec.name)) 76 | .returns(fieldSpec.type) 77 | .addModifiers(Modifier.PUBLIC) 78 | .addStatement("return this.$L", fieldSpec.name).build(); 79 | classBuilder.addMethod(getter); 80 | return this; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /BuildSrc/src/main/java/com/zjiecode/web/generator/generate/GenerateController.java: -------------------------------------------------------------------------------- 1 | package com.zjiecode.web.generator.generate; 2 | 3 | import com.squareup.javapoet.*; 4 | import com.zjiecode.web.generator.bean.FieldBean; 5 | import com.zjiecode.web.generator.utils.NameUtil; 6 | 7 | import javax.lang.model.element.Modifier; 8 | import java.util.ArrayList; 9 | import java.util.HashMap; 10 | import java.util.List; 11 | import java.util.Map; 12 | import java.util.concurrent.atomic.AtomicBoolean; 13 | 14 | /** 15 | * 生成Controller文件代码 16 | */ 17 | public class GenerateController extends GenerateBase { 18 | private TypeName serviceClassName; 19 | private ClassName resultClassName; 20 | 21 | public GenerateController(ClassName dependClass, String table, List fields, String basePackage) { 22 | super(dependClass, table, fields, basePackage, 23 | TypeSpec.classBuilder(NameUtil.className(table) + "Controller").addModifiers(Modifier.PUBLIC) 24 | .addAnnotation(AnnotationSpec.builder(ClassName.bestGuess("org.springframework.web.bind.annotation.RestController")).build()) 25 | .addAnnotation(AnnotationSpec.builder(ClassName.bestGuess("org.springframework.web.bind.annotation.RequestMapping")) 26 | .addMember("value", "\"/$L\"", table).build()) 27 | , "Controller"); 28 | resultClassName = ClassName.bestGuess(basePackage + ".base.result.Result"); 29 | } 30 | 31 | public void setServiceClassName(TypeName serviceClassName) { 32 | this.serviceClassName = serviceClassName; 33 | } 34 | 35 | //添加常见的增删改查的接口 36 | public GenerateController generate() { 37 | FieldSpec.Builder fieldBuilder = FieldSpec.builder(serviceClassName, "service", Modifier.PRIVATE); 38 | fieldBuilder.addAnnotation(AnnotationSpec.builder(ClassName.bestGuess("javax.annotation.Resource")).build()); 39 | classBuilder.addField(fieldBuilder.build()); 40 | insertMethod(); 41 | deleteMethod(); 42 | updateMethod(); 43 | findMethod(); 44 | findAll(); 45 | findByIdMethod(); 46 | count(); 47 | return this; 48 | } 49 | 50 | //生成返回的数据类型,套一层result 51 | private ParameterizedTypeName getReturnType(TypeName dataType) { 52 | return ParameterizedTypeName.get(resultClassName, dataType); 53 | } 54 | 55 | //生成插入数据的接口 56 | private void insertMethod() { 57 | MethodSpec.Builder builder = MethodSpec.methodBuilder("insert"); 58 | //参数验证的注解 59 | AnnotationSpec.Builder beanAnno = AnnotationSpec.builder(ClassName.bestGuess("javax.validation.Valid")); 60 | AnnotationSpec.Builder requestBodyAnno = AnnotationSpec.builder(ClassName.bestGuess("org.springframework.web.bind.annotation.RequestBody")); 61 | ParameterSpec.Builder beanParams = ParameterSpec.builder(beanClassName, table) 62 | .addAnnotation(beanAnno.build()) 63 | .addAnnotation(requestBodyAnno.build()); 64 | builder.addParameter(beanParams.build()); 65 | builder.addModifiers(Modifier.PUBLIC); 66 | builder.returns(getReturnType(beanClassName)); 67 | builder.addStatement("$L = service.insert($L)", table, table); 68 | CodeBlock.Builder codeBuilder = CodeBlock.builder(); 69 | codeBuilder.beginControlFlow("if ($L == null)", table); 70 | codeBuilder.addStatement("return $T.getBizFail(\"创建失败\")", resultClassName); 71 | codeBuilder.nextControlFlow("else"); 72 | codeBuilder.addStatement("return $T.getSuccess($L)", resultClassName, table); 73 | codeBuilder.endControlFlow(); 74 | builder.addCode(codeBuilder.build()); 75 | //post路由注解 76 | AnnotationSpec.Builder controllerAnno = AnnotationSpec.builder(ClassName.bestGuess("org.springframework.web.bind.annotation.PostMapping")); 77 | controllerAnno.addMember("value", "\"\""); 78 | builder.addAnnotation(controllerAnno.build()); 79 | classBuilder.addMethod(builder.build()); 80 | } 81 | 82 | //生成删除数据的接口 83 | private void deleteMethod() { 84 | MethodSpec.Builder builder = MethodSpec.methodBuilder("delete"); 85 | builder.returns(resultClassName); 86 | builder.addModifiers(Modifier.PUBLIC); 87 | CodeBlock.Builder codeBuilder = CodeBlock.builder(); 88 | codeBuilder.beginControlFlow("if (ids != null && !ids.isEmpty())"); 89 | codeBuilder.addStatement("$T<$T> successIds = new $T<>()", List.class, Integer.class, ArrayList.class); 90 | codeBuilder.addStatement("boolean completeOne = false"); 91 | codeBuilder.beginControlFlow("for ($T id : ids)", Integer.class); 92 | codeBuilder.addStatement("boolean delete = service.delete(id)"); 93 | codeBuilder.beginControlFlow("if (delete)"); 94 | codeBuilder.addStatement(" successIds.add(id)"); 95 | codeBuilder.endControlFlow(); 96 | codeBuilder.addStatement("completeOne = delete || completeOne"); 97 | codeBuilder.endControlFlow(); 98 | codeBuilder.beginControlFlow("if (!completeOne)"); 99 | codeBuilder.addStatement("return $T.getBizFail(\"不存在或已经被删除\")", resultClassName); 100 | codeBuilder.nextControlFlow(" else"); 101 | codeBuilder.addStatement("return new $T($T.SUCCESS, (successIds.size() == ids.size())?\"删除成功\":\"部分删除成功\", successIds.size())", resultClassName, ClassName.bestGuess(basePackage + ".base.result.ResultCode")); 102 | codeBuilder.endControlFlow(); 103 | codeBuilder.endControlFlow(); 104 | codeBuilder.addStatement("return $T.getBizFail(\"删除id不能为空\")", resultClassName); 105 | builder.addCode(codeBuilder.build()); 106 | 107 | //delete路由注解 108 | AnnotationSpec.Builder controllerAnno = AnnotationSpec.builder(ClassName.bestGuess("org.springframework.web.bind.annotation.DeleteMapping")); 109 | controllerAnno.addMember("value", "\"\""); 110 | builder.addAnnotation(controllerAnno.build()); 111 | //函数参数注解 112 | ParameterSpec.Builder idParams = ParameterSpec.builder(ParameterizedTypeName.get(List.class, Integer.class), "ids"); 113 | AnnotationSpec.Builder requestBodyAnno = AnnotationSpec.builder(ClassName.bestGuess("org.springframework.web.bind.annotation.RequestBody")); 114 | idParams.addAnnotation(requestBodyAnno.build()); 115 | builder.addParameter(idParams.build()); 116 | classBuilder.addMethod(builder.build()); 117 | } 118 | 119 | 120 | //生成修改的接口 121 | private void updateMethod() { 122 | MethodSpec.Builder builder = MethodSpec.methodBuilder("update"); 123 | builder.returns(getReturnType(ClassName.BOOLEAN.box())); 124 | builder.addModifiers(Modifier.PUBLIC); 125 | AtomicBoolean hasId = new AtomicBoolean(false); 126 | fields.stream().forEach(field -> { 127 | if ("id".equals(field.getName())) { 128 | hasId.set(true); 129 | return; 130 | } 131 | }); 132 | builder.beginControlFlow("if ($L.getId() == null || $L.getId() == 0)", table, table); 133 | builder.addStatement("return $T.getBizFail(\"请提供需要更新的记录id\")", resultClassName); 134 | builder.nextControlFlow("else"); 135 | builder.addStatement("boolean update = service.update($L)", table); 136 | CodeBlock.Builder codeBuilder = CodeBlock.builder(); 137 | codeBuilder.beginControlFlow("if (update)"); 138 | codeBuilder.addStatement("return $T.getSuccess(true)", resultClassName); 139 | codeBuilder.nextControlFlow("else"); 140 | codeBuilder.addStatement("return $T.getBizFail(\"更新失败或数据不存在\")", resultClassName); 141 | codeBuilder.endControlFlow(); 142 | codeBuilder.endControlFlow(); 143 | builder.addCode(codeBuilder.build()); 144 | 145 | //put路由注解 146 | AnnotationSpec.Builder controllerAnno = AnnotationSpec.builder(ClassName.bestGuess("org.springframework.web.bind.annotation.PutMapping")); 147 | controllerAnno.addMember("value", "\"\""); 148 | builder.addAnnotation(controllerAnno.build()); 149 | //函数参数注解 150 | ParameterSpec.Builder idParams = ParameterSpec.builder(beanClassName, table); 151 | AnnotationSpec.Builder requestBodyAnno = AnnotationSpec.builder(ClassName.bestGuess("org.springframework.web.bind.annotation.RequestBody")); 152 | idParams.addAnnotation(requestBodyAnno.build()); 153 | builder.addParameter(idParams.build()); 154 | classBuilder.addMethod(builder.build()); 155 | } 156 | 157 | //分页列表查询 158 | private void findMethod() { 159 | MethodSpec.Builder builder = MethodSpec.methodBuilder("find"); 160 | builder.returns(resultClassName); 161 | builder.addModifiers(Modifier.PUBLIC); 162 | builder.addStatement("return $T.getSuccess(service.find($L, pageIndex, pageSize))", resultClassName, table); 163 | //get路由注解 164 | AnnotationSpec.Builder controllerAnno = AnnotationSpec.builder(ClassName.bestGuess("org.springframework.web.bind.annotation.GetMapping")); 165 | controllerAnno.addMember("value", "\"\""); 166 | builder.addAnnotation(controllerAnno.build()); 167 | //函数参数注解 168 | ParameterSpec.Builder beanParams = ParameterSpec.builder(beanClassName, table); 169 | ParameterSpec.Builder pageIndexParams = ParameterSpec.builder(Integer.class, "pageIndex"); 170 | ParameterSpec.Builder pageSizeParams = ParameterSpec.builder(Integer.class, "pageSize"); 171 | builder.addParameter(beanParams.build()); 172 | builder.addParameter(pageIndexParams.build()); 173 | builder.addParameter(pageSizeParams.build()); 174 | classBuilder.addMethod(builder.build()); 175 | } 176 | 177 | //根据id查询详情 178 | private void findByIdMethod() { 179 | MethodSpec.Builder builder = MethodSpec.methodBuilder("findById"); 180 | builder.returns(getReturnType(beanClassName)); 181 | builder.addModifiers(Modifier.PUBLIC); 182 | builder.addStatement("return $T.getSuccess(service.findById(id))", resultClassName); 183 | //get路由注解 184 | AnnotationSpec.Builder controllerAnno = AnnotationSpec.builder(ClassName.bestGuess("org.springframework.web.bind.annotation.GetMapping")); 185 | controllerAnno.addMember("value", "\"/detail\""); 186 | builder.addAnnotation(controllerAnno.build()); 187 | //函数参数注解 188 | ParameterSpec.Builder idParams = ParameterSpec.builder(Integer.class, "id"); 189 | builder.addParameter(idParams.build()); 190 | classBuilder.addMethod(builder.build()); 191 | } 192 | 193 | //查询全部 194 | private void findAll() { 195 | MethodSpec.Builder builder = MethodSpec.methodBuilder("findAll"); 196 | builder.returns(getReturnType(ParameterizedTypeName.get(ClassName.get(List.class), beanClassName))); 197 | builder.addModifiers(Modifier.PUBLIC); 198 | builder.addStatement("return $T.getSuccess(service.findAll())", resultClassName); 199 | //get路由注解 200 | AnnotationSpec.Builder controllerAnno = AnnotationSpec.builder(ClassName.bestGuess("org.springframework.web.bind.annotation.GetMapping")); 201 | controllerAnno.addMember("value", "\"/all\""); 202 | builder.addAnnotation(controllerAnno.build()); 203 | classBuilder.addMethod(builder.build()); 204 | } 205 | 206 | //查询存在的记录条数 207 | private void count() { 208 | MethodSpec.Builder builder = MethodSpec.methodBuilder("count"); 209 | builder.returns(getReturnType(ClassName.INT.box())); 210 | builder.addModifiers(Modifier.PUBLIC); 211 | 212 | builder.addStatement("return $T.getSuccess(service.count())", resultClassName); 213 | //get路由注解 214 | AnnotationSpec.Builder controllerAnno = AnnotationSpec.builder(ClassName.bestGuess("org.springframework.web.bind.annotation.GetMapping")); 215 | controllerAnno.addMember("value", "\"/count\""); 216 | builder.addAnnotation(controllerAnno.build()); 217 | classBuilder.addMethod(builder.build()); 218 | } 219 | } 220 | -------------------------------------------------------------------------------- /BuildSrc/src/main/java/com/zjiecode/web/generator/generate/GenerateMapper.java: -------------------------------------------------------------------------------- 1 | package com.zjiecode.web.generator.generate; 2 | 3 | import com.squareup.javapoet.*; 4 | import com.zjiecode.web.generator.GenerateException; 5 | import com.zjiecode.web.generator.bean.FieldBean; 6 | import com.zjiecode.web.generator.utils.NameUtil; 7 | 8 | import javax.lang.model.element.Modifier; 9 | import java.util.List; 10 | 11 | /** 12 | * 生成mapper文件代码 13 | */ 14 | public class GenerateMapper extends GenerateBase { 15 | private TypeName sqlProviderClassName; 16 | private String fieldMapping; 17 | 18 | public GenerateMapper(ClassName dependClass, String table, List fields, String basePackage) { 19 | super(dependClass, table, fields, basePackage, 20 | TypeSpec.interfaceBuilder(NameUtil.className(table) + "Mapper").addModifiers(Modifier.PUBLIC) 21 | .addAnnotation(AnnotationSpec.builder(ClassName.bestGuess("org.apache.ibatis.annotations.Mapper")).build()) 22 | , "Mapper"); 23 | //生成db field 到bean的名字映射 24 | StringBuilder sbKey = new StringBuilder(); 25 | fields.stream().forEach(field -> { 26 | sbKey.append("`" + field.getName() + "`"); 27 | sbKey.append(" AS "); 28 | sbKey.append(NameUtil.fieldName(field.getName())); 29 | sbKey.append(","); 30 | }); 31 | sbKey.deleteCharAt(sbKey.length() - 1); 32 | fieldMapping = sbKey.toString(); 33 | } 34 | 35 | public void setSqlProviderClassName(TypeName sqlProviderClassName) { 36 | this.sqlProviderClassName = sqlProviderClassName; 37 | } 38 | 39 | //添加常见的增删改查的接口 40 | public GenerateMapper generate() { 41 | insertMethod(); 42 | deleteMethod(); 43 | updateMethod(); 44 | findByIdMethod(); 45 | findAll(); 46 | find(); 47 | count(); 48 | return this; 49 | } 50 | 51 | private String getFieldMapping() { 52 | StringBuilder sbKey = new StringBuilder(); 53 | fields.stream().forEach(field -> { 54 | sbKey.append("`" + field.getName() + "`"); 55 | sbKey.append(" AS "); 56 | sbKey.append(NameUtil.fieldName(field.getName())); 57 | sbKey.append(","); 58 | }); 59 | sbKey.deleteCharAt(sbKey.length() - 1); 60 | return sbKey.toString(); 61 | } 62 | 63 | //生成插入数据的接口 64 | private void insertMethod() { 65 | MethodSpec.Builder insertBuilder = MethodSpec.methodBuilder("insert"); 66 | insertBuilder.addParameter(beanClassName, table); 67 | //sql注解 68 | AnnotationSpec.Builder insertAnno = AnnotationSpec.builder(ClassName.bestGuess("org.apache.ibatis.annotations.Insert")); 69 | StringBuilder sbKey = new StringBuilder(); 70 | StringBuilder sbValue = new StringBuilder(); 71 | fields.stream().forEach(field -> { 72 | sbKey.append("`" + field.getName() + "`").append(","); 73 | sbValue.append("#{").append(NameUtil.fieldName(field.getName())).append("}").append(","); 74 | }); 75 | if (sbKey.length() <= 0) { 76 | throw new GenerateException("表[" + table + "]字段不能为空"); 77 | } 78 | sbKey.deleteCharAt(sbKey.length() - 1); 79 | sbValue.deleteCharAt(sbValue.length() - 1); 80 | insertAnno.addMember("value", "\"INSERT INTO `$L`($L) VALUES($L)\"", table, sbKey.toString(), sbValue.toString()); 81 | insertBuilder.addAnnotation(insertAnno.build()); 82 | //获取插入的id的注解 83 | AnnotationSpec.Builder autoAnno = AnnotationSpec.builder(ClassName.bestGuess("org.apache.ibatis.annotations.Options")); 84 | autoAnno.addMember("useGeneratedKeys", "true"); 85 | insertBuilder.addAnnotation(autoAnno.build()); 86 | 87 | insertBuilder.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT); 88 | insertBuilder.returns(Boolean.class); 89 | classBuilder.addMethod(insertBuilder.build()); 90 | } 91 | 92 | //生成删除数据的接口 93 | private void deleteMethod() { 94 | MethodSpec.Builder deleteBuilder = MethodSpec.methodBuilder("delete"); 95 | deleteBuilder.addParameter(Integer.class, "id"); 96 | deleteBuilder.returns(Boolean.class); 97 | AnnotationSpec.Builder deleteAnno = AnnotationSpec.builder(ClassName.bestGuess("org.apache.ibatis.annotations.Delete")); 98 | deleteAnno.addMember("value", "\"delete from `$L` where id=#{id}\"", table); 99 | deleteBuilder.addAnnotation(deleteAnno.build()); 100 | deleteBuilder.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT); 101 | classBuilder.addMethod(deleteBuilder.build()); 102 | } 103 | 104 | 105 | //生成修改的接口 106 | private void updateMethod() { 107 | MethodSpec.Builder builder = MethodSpec.methodBuilder("update"); 108 | builder.addParameter(beanClassName, table); 109 | builder.returns(Boolean.class); 110 | AnnotationSpec.Builder upateAnno = AnnotationSpec.builder(ClassName.bestGuess("org.apache.ibatis.annotations.UpdateProvider")); 111 | upateAnno.addMember("type", "$T.class", sqlProviderClassName); 112 | upateAnno.addMember("method", "$S", "update"); 113 | builder.addAnnotation(upateAnno.build()); 114 | builder.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT); 115 | classBuilder.addMethod(builder.build()); 116 | } 117 | 118 | //根据id查询记录 119 | private void findByIdMethod() { 120 | MethodSpec.Builder builder = MethodSpec.methodBuilder("findById"); 121 | builder.addParameter(Integer.class, "id"); 122 | builder.returns(beanClassName); 123 | AnnotationSpec.Builder anno = AnnotationSpec.builder(ClassName.bestGuess("org.apache.ibatis.annotations.Select")); 124 | anno.addMember("value", "\"SELECT $L FROM `$L` WHERE id = #{id}\"", fieldMapping, table); 125 | builder.addAnnotation(anno.build()); 126 | builder.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT); 127 | classBuilder.addMethod(builder.build()); 128 | } 129 | 130 | //查询全部 131 | private void findAll() { 132 | MethodSpec.Builder builder = MethodSpec.methodBuilder("findAll"); 133 | builder.returns(ParameterizedTypeName.get(ClassName.get(List.class), beanClassName)); 134 | AnnotationSpec.Builder anno = AnnotationSpec.builder(ClassName.bestGuess("org.apache.ibatis.annotations.Select")); 135 | anno.addMember("value", "\"SELECT $L FROM `$L`\"", fieldMapping, table); 136 | builder.addAnnotation(anno.build()); 137 | builder.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT); 138 | classBuilder.addMethod(builder.build()); 139 | } 140 | 141 | //分页代条件查询 142 | private void find() { 143 | MethodSpec.Builder builder = MethodSpec.methodBuilder("find"); 144 | builder.addParameter(beanClassName, table); 145 | builder.returns(ParameterizedTypeName.get(ClassName.get(List.class), beanClassName)); 146 | AnnotationSpec.Builder upateAnno = AnnotationSpec.builder(ClassName.bestGuess("org.apache.ibatis.annotations.SelectProvider")); 147 | upateAnno.addMember("type", "$T.class", sqlProviderClassName); 148 | upateAnno.addMember("method", "$S", "find"); 149 | builder.addAnnotation(upateAnno.build()); 150 | builder.addParameter(ParameterSpec.builder(Integer.class, "pageIndex").build()); 151 | builder.addParameter(ParameterSpec.builder(Integer.class, "pageSize").build()); 152 | builder.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT); 153 | classBuilder.addMethod(builder.build()); 154 | } 155 | 156 | //查询存在的记录条数 157 | private void count() { 158 | MethodSpec.Builder builder = MethodSpec.methodBuilder("count"); 159 | builder.returns(Integer.class); 160 | AnnotationSpec.Builder anno = AnnotationSpec.builder(ClassName.bestGuess("org.apache.ibatis.annotations.Select")); 161 | anno.addMember("value", "\"SELECT count(1) FROM `$L`\"", table); 162 | builder.addAnnotation(anno.build()); 163 | builder.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT); 164 | classBuilder.addMethod(builder.build()); 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /BuildSrc/src/main/java/com/zjiecode/web/generator/generate/GenerateService.java: -------------------------------------------------------------------------------- 1 | package com.zjiecode.web.generator.generate; 2 | 3 | import com.squareup.javapoet.*; 4 | import com.zjiecode.web.generator.bean.FieldBean; 5 | import com.zjiecode.web.generator.utils.NameUtil; 6 | 7 | import javax.lang.model.element.Modifier; 8 | import java.util.List; 9 | 10 | /** 11 | * 生成Service文件代码 12 | */ 13 | public class GenerateService extends GenerateBase { 14 | private TypeName mapperClassName; 15 | 16 | public GenerateService(ClassName dependClass, String table, List fields, String basePackage) { 17 | super(dependClass, table, fields, basePackage, 18 | TypeSpec.classBuilder(NameUtil.className(table) + "Service").addModifiers(Modifier.PUBLIC) 19 | .addAnnotation(AnnotationSpec.builder(ClassName.bestGuess("org.springframework.stereotype.Service")).build()) 20 | , "Service"); 21 | } 22 | 23 | public void setMapperClassName(TypeName mapperClassName) { 24 | this.mapperClassName = mapperClassName; 25 | } 26 | 27 | //添加常见的增删改查的接口 28 | public GenerateService generate() { 29 | FieldSpec.Builder fieldBuilder = FieldSpec.builder(mapperClassName, "mapper", Modifier.PRIVATE); 30 | fieldBuilder.addAnnotation(AnnotationSpec.builder(ClassName.bestGuess("javax.annotation.Resource")).build()); 31 | classBuilder.addField(fieldBuilder.build()); 32 | insertMethod(); 33 | deleteMethod(); 34 | updateMethod(); 35 | findByIdMethod(); 36 | findAll(); 37 | findAllByPage(); 38 | count(); 39 | return this; 40 | } 41 | 42 | //生成插入数据的接口 43 | private void insertMethod() { 44 | MethodSpec.Builder builder = MethodSpec.methodBuilder("insert"); 45 | builder.addParameter(beanClassName, table); 46 | builder.addModifiers(Modifier.PUBLIC); 47 | builder.returns(beanClassName); 48 | builder.beginControlFlow("if (mapper.insert($L))", table); 49 | builder.addStatement("return $L", table); 50 | builder.nextControlFlow("else"); 51 | builder.addStatement("return null"); 52 | builder.endControlFlow(); 53 | classBuilder.addMethod(builder.build()); 54 | } 55 | 56 | //生成删除数据的接口 57 | private void deleteMethod() { 58 | MethodSpec.Builder builder = MethodSpec.methodBuilder("delete"); 59 | builder.addParameter(Integer.class, "id"); 60 | builder.returns(Boolean.class); 61 | builder.addModifiers(Modifier.PUBLIC); 62 | builder.addStatement("return mapper.delete(id)"); 63 | classBuilder.addMethod(builder.build()); 64 | } 65 | 66 | 67 | //生成修改的接口 68 | private void updateMethod() { 69 | MethodSpec.Builder builder = MethodSpec.methodBuilder("update"); 70 | builder.addParameter(beanClassName, table); 71 | builder.returns(Boolean.class); 72 | builder.addModifiers(Modifier.PUBLIC); 73 | builder.addStatement("return mapper.update($L)", table); 74 | classBuilder.addMethod(builder.build()); 75 | } 76 | 77 | //根据id查询记录详情 78 | private void findByIdMethod() { 79 | MethodSpec.Builder builder = MethodSpec.methodBuilder("findById"); 80 | builder.addParameter(Integer.class, "id"); 81 | builder.returns(beanClassName); 82 | builder.addModifiers(Modifier.PUBLIC); 83 | builder.addStatement("return mapper.findById(id)"); 84 | classBuilder.addMethod(builder.build()); 85 | } 86 | 87 | //查询全部 88 | private void findAll() { 89 | MethodSpec.Builder builder = MethodSpec.methodBuilder("findAll"); 90 | builder.returns(ParameterizedTypeName.get(ClassName.get(List.class), beanClassName)); 91 | builder.addModifiers(Modifier.PUBLIC); 92 | builder.addStatement("return mapper.findAll()"); 93 | classBuilder.addMethod(builder.build()); 94 | } 95 | 96 | //分页查询 97 | private void findAllByPage() { 98 | MethodSpec.Builder builder = MethodSpec.methodBuilder("find"); 99 | builder.addModifiers(Modifier.PUBLIC); 100 | builder.returns(ParameterizedTypeName.get(ClassName.bestGuess(basePackage + ".base.Pagination"), ParameterizedTypeName.get(ClassName.get(List.class), beanClassName))); 101 | builder.addParameter(ParameterSpec.builder(beanClassName, table).build()); 102 | builder.addParameter(ParameterSpec.builder(Integer.class, "pageIndex").build()); 103 | builder.addParameter(ParameterSpec.builder(Integer.class, "pageSize").build()); 104 | builder.beginControlFlow("if(pageIndex==null || pageIndex < 1)"); 105 | builder.addStatement("pageIndex=1"); 106 | builder.endControlFlow(); 107 | 108 | builder.beginControlFlow("if(pageSize==null || pageSize < 1)"); 109 | builder.addStatement("pageSize=20"); 110 | builder.endControlFlow(); 111 | 112 | builder.addStatement("$T<$T> records = mapper.find($L,(pageIndex - 1) * pageSize, pageSize)", List.class, beanClassName, table); 113 | builder.addStatement("return new $T(mapper.count(), pageIndex, records)", ClassName.bestGuess(basePackage + ".base.Pagination")); 114 | classBuilder.addMethod(builder.build()); 115 | } 116 | 117 | 118 | //查询存在的记录条数 119 | private void count() { 120 | MethodSpec.Builder builder = MethodSpec.methodBuilder("count"); 121 | builder.returns(Integer.class); 122 | builder.addModifiers(Modifier.PUBLIC); 123 | builder.addStatement("return mapper.count()"); 124 | classBuilder.addMethod(builder.build()); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /BuildSrc/src/main/java/com/zjiecode/web/generator/generate/GenerateSqlProvider.java: -------------------------------------------------------------------------------- 1 | package com.zjiecode.web.generator.generate; 2 | 3 | import com.squareup.javapoet.*; 4 | import com.zjiecode.web.generator.bean.FieldBean; 5 | import com.zjiecode.web.generator.utils.NameUtil; 6 | 7 | import javax.lang.model.element.Modifier; 8 | import java.util.List; 9 | 10 | /** 11 | * 生成mapper文件代码 12 | */ 13 | public class GenerateSqlProvider extends GenerateBase { 14 | public GenerateSqlProvider(ClassName dependClass, String table, List fields, String basePackage) { 15 | super(dependClass, table, fields, basePackage, 16 | TypeSpec.classBuilder(NameUtil.className(table) + "SqlProvider").addModifiers(Modifier.PUBLIC), 17 | "SqlProvider"); 18 | } 19 | 20 | //添加常见的增删改查的接口 21 | public void generate() { 22 | generateUpdate(); 23 | generateFind(); 24 | } 25 | 26 | private void generateUpdate() { 27 | MethodSpec.Builder updateBuilder = MethodSpec.methodBuilder("update"); 28 | updateBuilder.addParameter(beanClassName, table); 29 | updateBuilder.addException(Exception.class); 30 | updateBuilder.returns(String.class); 31 | updateBuilder.addStatement("$T sb = new $T()", StringBuilder.class, StringBuilder.class); 32 | fields.stream().forEach(field -> { 33 | updateBuilder.beginControlFlow("if (null!=$L.get$L())", table, NameUtil.className(field.getName())) 34 | .addStatement("sb.append(\",$L = #{$L}\")", field.getName(), NameUtil.fieldName(field.getName())) 35 | .endControlFlow(); 36 | }); 37 | ClassName BizException = ClassName.bestGuess(basePackage + ".base.exception.BizException"); 38 | updateBuilder.beginControlFlow("if (sb.length() == 0)") 39 | .addStatement(" throw new $T(\"没有需要更新的字段\")", BizException) 40 | .endControlFlow(); 41 | fields.stream().forEach(field -> { 42 | if ("id".equalsIgnoreCase(field.getName())) { 43 | updateBuilder.beginControlFlow("if ($L.getId() == null ||\"\".equals($L.getId()))", table, table) 44 | .addStatement(" throw new $T(\"请提供更新的数据主键\")", BizException) 45 | .endControlFlow(); 46 | } 47 | }); 48 | updateBuilder.addStatement("sb.append(\" where id=#{id}\")"); 49 | updateBuilder.addStatement("sb.deleteCharAt(0)"); 50 | updateBuilder.addStatement("sb.insert(0, \"update $L set \")",table); 51 | updateBuilder.addStatement("return sb.toString()"); 52 | updateBuilder.addModifiers(Modifier.PUBLIC); 53 | classBuilder.addMethod(updateBuilder.build()); 54 | } 55 | 56 | private void generateFind() { 57 | MethodSpec.Builder findBuilder = MethodSpec.methodBuilder("find"); 58 | findBuilder.addModifiers(Modifier.PUBLIC); 59 | findBuilder.addParameter(beanClassName, table); 60 | findBuilder.addParameter(Integer.class, "pageIndex"); 61 | findBuilder.addParameter(Integer.class, "pageSize"); 62 | findBuilder.addException(Exception.class); 63 | findBuilder.returns(String.class); 64 | findBuilder.addStatement("$T sb = new $T()", StringBuilder.class, StringBuilder.class); 65 | fields.stream().forEach(field -> { 66 | findBuilder.beginControlFlow("if (null!=$L.get$L())", table, NameUtil.className(field.getName())) 67 | .addStatement("sb.append(\" and $L = #{arg0.$L}\")", field.getName(),NameUtil.fieldName(field.getName())) 68 | .endControlFlow(); 69 | }); 70 | findBuilder.beginControlFlow("if (sb.length() != 0)"); 71 | findBuilder.addStatement("sb.delete(0, 5)"); 72 | findBuilder.addStatement("sb.insert(0, \" where \")"); 73 | findBuilder.endControlFlow(); 74 | 75 | findBuilder.beginControlFlow("if (pageIndex == null || pageIndex == 0)"); 76 | findBuilder.addStatement("pageIndex = 1"); 77 | findBuilder.endControlFlow(); 78 | 79 | findBuilder.beginControlFlow("if (pageSize == null || pageSize == 0)"); 80 | findBuilder.addStatement("pageSize = 20"); 81 | findBuilder.endControlFlow(); 82 | 83 | findBuilder.addStatement("sb.append(\" limit \")"); 84 | findBuilder.addStatement("sb.append((pageIndex - 1) * pageSize)"); 85 | findBuilder.addStatement("sb.append(\",\")"); 86 | findBuilder.addStatement("sb.append(pageSize)"); 87 | 88 | 89 | findBuilder.addStatement("$T fields = new $T()", StringBuilder.class, StringBuilder.class); 90 | findBuilder.addStatement("fields.append(\"SELECT \")"); 91 | 92 | for (int i = 0; i < fields.size(); i++) { 93 | FieldBean field = fields.get(i); 94 | findBuilder.addStatement("fields.append(\" `$L` as $L" + ((i < fields.size() - 1) ? "," : "") + "\")", field.getName(), NameUtil.fieldName(field.getName())); 95 | } 96 | findBuilder.addStatement("fields.append(\" from $L\")", table); 97 | findBuilder.addStatement("String sql = fields.toString() + sb.toString()"); 98 | findBuilder.addStatement("return sql"); 99 | 100 | 101 | classBuilder.addMethod(findBuilder.build()); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /BuildSrc/src/main/java/com/zjiecode/web/generator/utils/FieldTypeUtil.java: -------------------------------------------------------------------------------- 1 | package com.zjiecode.web.generator.utils; 2 | 3 | import com.squareup.javapoet.ArrayTypeName; 4 | import com.squareup.javapoet.ClassName; 5 | import com.squareup.javapoet.TypeName; 6 | import com.zjiecode.web.generator.bean.FieldBean; 7 | 8 | import java.lang.reflect.Type; 9 | import java.math.BigDecimal; 10 | import java.util.Date; 11 | import java.util.HashMap; 12 | import java.util.Map; 13 | 14 | /** 15 | * mysql数据库字段类型到java的映射 16 | */ 17 | public class FieldTypeUtil { 18 | private static final Map typeMaps = new HashMap<>(); 19 | 20 | static { 21 | typeMaps.put("bit", ArrayTypeName.of(Byte.class)); 22 | typeMaps.put("tinyint", Byte.class); 23 | typeMaps.put("binary", ArrayTypeName.of(Byte.class)); 24 | typeMaps.put("blob", ArrayTypeName.of(Byte.class)); 25 | typeMaps.put("integer", Integer.class); 26 | typeMaps.put("int", Integer.class); 27 | typeMaps.put("bigint", Long.class); 28 | typeMaps.put("double", Double.class); 29 | typeMaps.put("float", Float.class); 30 | typeMaps.put("decimal", BigDecimal.class); 31 | typeMaps.put("date", Date.class); 32 | typeMaps.put("datetime", Date.class); 33 | typeMaps.put("text", String.class); 34 | } 35 | 36 | public static Object getType(FieldBean fieldBean) { 37 | if ("bit".equals(fieldBean.getType().toLowerCase()) && fieldBean.getLength() == 1) { 38 | return Boolean.class; 39 | } else { 40 | Object type = typeMaps.get(fieldBean.getType().toLowerCase()); 41 | if (type == null) { 42 | type = String.class; 43 | } 44 | return type; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /BuildSrc/src/main/java/com/zjiecode/web/generator/utils/FileResList.java: -------------------------------------------------------------------------------- 1 | package com.zjiecode.web.generator.utils; 2 | 3 | import com.zjiecode.web.generator.bean.FileResBean; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | public class FileResList { 9 | private List resList = new ArrayList<>(); 10 | private List javaList = new ArrayList<>(); 11 | private static final FileResList instance = new FileResList(); 12 | 13 | private FileResList() { 14 | //资源配置文件,目的文件地址,是以资源文件根目录为地址的 15 | resList.add(new FileResBean("/config/banner.txt", "banner.txt")); 16 | resList.add(new FileResBean("/config/application.properties", "application.properties")); 17 | resList.add(new FileResBean("/config/application-dev.properties", "application-dev.properties")); 18 | resList.add(new FileResBean("/config/application-prod.properties", "application-prod.properties")); 19 | //固定的java文件 20 | javaList.add(new FileResBean("/java/exception/AppException.java", "base/exception/AppException.java")); 21 | javaList.add(new FileResBean("/java/exception/BizException.java", "base/exception/BizException.java")); 22 | javaList.add(new FileResBean("/java/result/Result.java", "base/result/Result.java")); 23 | javaList.add(new FileResBean("/java/result/ResultCode.java", "base/result/ResultCode.java")); 24 | javaList.add(new FileResBean("/java/AppWebMvcConfigurer.java", "base/AppWebMvcConfigurer.java")); 25 | javaList.add(new FileResBean("/java/Pagination.java", "base/Pagination.java")); 26 | javaList.add(new FileResBean("/java/JavaWebApplication.java", "JavaWebApplication.java")); 27 | } 28 | 29 | public static FileResList getInstance() { 30 | return instance; 31 | } 32 | 33 | public List getJavaList() { 34 | return javaList; 35 | } 36 | 37 | public List getResList() { 38 | return resList; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /BuildSrc/src/main/java/com/zjiecode/web/generator/utils/NameUtil.java: -------------------------------------------------------------------------------- 1 | package com.zjiecode.web.generator.utils; 2 | 3 | public class NameUtil { 4 | /** 5 | * 生成类名,也就是首字母大写 6 | * 7 | * @param name 8 | * @return 9 | */ 10 | public static String className(String name) { 11 | if (name != null) { 12 | String[] words = name.split("_"); 13 | StringBuilder finalClassName = new StringBuilder(); 14 | if (words.length > 0) { 15 | for (String s : words) { 16 | finalClassName.append(s.substring(0, 1).toUpperCase() + s.substring(1)); 17 | } 18 | } 19 | name = finalClassName.toString(); 20 | } 21 | return name; 22 | } 23 | 24 | /** 25 | * 生成字段名,驼峰命名法 26 | * 27 | * @param name 28 | * @return 29 | */ 30 | public static String fieldName(String name) { 31 | if (name != null) { 32 | String[] words = name.split("_"); 33 | StringBuilder fieldName = new StringBuilder(); 34 | if (words.length > 0) { 35 | for (String s : words) { 36 | if (fieldName.length() == 0) { 37 | fieldName.append(s.substring(0, 1).toLowerCase() + s.substring(1)); 38 | } else { 39 | fieldName.append(s.substring(0, 1).toUpperCase() + s.substring(1)); 40 | } 41 | } 42 | } 43 | name = fieldName.toString(); 44 | } 45 | return name; 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /BuildSrc/src/main/java/com/zjiecode/web/generator/utils/PathUtil.java: -------------------------------------------------------------------------------- 1 | package com.zjiecode.web.generator.utils; 2 | 3 | import java.io.File; 4 | 5 | public class PathUtil { 6 | //生成代码存放根目录 7 | public static File SRC_ROOT_DIR = new File("src/main/java/"); 8 | public static File RES_ROOT_DIR = new File("src/main/resources/"); 9 | 10 | //把包名变成路径 11 | public static String package2Path(String path) { 12 | return path.replace('.', '/'); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /BuildSrc/src/main/resources/META-INF/gradle-plugins/javaweb-api-generate.properties: -------------------------------------------------------------------------------- 1 | implementation-class=com.zjiecode.web.generator.WebApiCodeGeneratePlugin -------------------------------------------------------------------------------- /BuildSrc/src/main/resources/config/application-dev.properties: -------------------------------------------------------------------------------- 1 | #jdbc 开发环境配置 2 | spring.datasource.driver=com.mysql.jdbc.Driver 3 | spring.datasource.url=jdbc:mysql://${host}:${port}/${dbName}?useUnicode=true&characterEncoding=utf8&useSSL=false 4 | spring.datasource.username=${user} 5 | spring.datasource.password=${pwd} 6 | spring.datasource.maxActive=2335 7 | spring.datasource.maxIdel=120 8 | spring.datasource.maxWait=100 9 | 10 | #打印sql 11 | logging.level.com.smjcco.pangu.api.biz=debug 12 | #端口 13 | server.port=8001 -------------------------------------------------------------------------------- /BuildSrc/src/main/resources/config/application-prod.properties: -------------------------------------------------------------------------------- 1 | #jdbc 生产环境,请自行配置 2 | spring.datasource.driver=com.mysql.jdbc.Driver 3 | spring.datasource.url=jdbc:mysql://127.0.0.1:3306/spring_boot_demo?useUnicode=true&characterEncoding=utf8&useSSL=false 4 | spring.datasource.username=root 5 | spring.datasource.password=123456 6 | spring.datasource.maxActive=2335 7 | spring.datasource.maxIdel=120 8 | spring.datasource.maxWait=100 -------------------------------------------------------------------------------- /BuildSrc/src/main/resources/config/application.properties: -------------------------------------------------------------------------------- 1 | #选择环境配置 2 | spring.profiles.active=dev 3 | 4 | # 404 交给异常处理器处理 5 | spring.mvc.throw-exception-if-no-handler-found=true 6 | spring.resources.add-mappings=false 7 | 8 | #应用程序配置 9 | #数据签名的密钥 10 | privateKey=123abc 11 | #服务器和客户端允许的最大时间差,单位是毫秒 12 | maxTimeGap=1800000 -------------------------------------------------------------------------------- /BuildSrc/src/main/resources/config/banner.txt: -------------------------------------------------------------------------------- 1 | 2 | ===============系统启动中================= 3 | 4 | 本系统使用javaweb-api-generate生成。 5 | 欢迎访问github,提供帮助或者建议:https://github.com/zjiecode/javaweb-api-generate 6 | 7 | ===============系统启动中================= -------------------------------------------------------------------------------- /BuildSrc/src/main/resources/java/AppWebMvcConfigurer.java: -------------------------------------------------------------------------------- 1 | package ${package}.base; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | import ${package}.base.exception.AppException; 5 | import ${package}.base.exception.BizException; 6 | import ${package}.base.result.Result; 7 | import ${package}.base.result.ResultCode; 8 | 9 | import com.fasterxml.jackson.databind.ObjectMapper; 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | import org.springframework.beans.factory.annotation.Value; 13 | import org.springframework.context.annotation.Configuration; 14 | import org.springframework.util.DigestUtils; 15 | import org.springframework.util.StringUtils; 16 | import org.springframework.validation.BindException; 17 | import org.springframework.validation.ObjectError; 18 | import org.springframework.web.HttpRequestMethodNotSupportedException; 19 | import org.springframework.web.bind.MethodArgumentNotValidException; 20 | import org.springframework.web.servlet.HandlerExceptionResolver; 21 | import org.springframework.web.servlet.HandlerInterceptor; 22 | import org.springframework.web.servlet.ModelAndView; 23 | import org.springframework.web.servlet.NoHandlerFoundException; 24 | import org.springframework.web.servlet.config.annotation.CorsRegistry; 25 | import org.springframework.web.servlet.config.annotation.InterceptorRegistry; 26 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 27 | 28 | import javax.servlet.ServletException; 29 | import javax.servlet.http.HttpServletRequest; 30 | import javax.servlet.http.HttpServletResponse; 31 | import java.io.IOException; 32 | import java.util.ArrayList; 33 | import java.util.Collections; 34 | import java.util.List; 35 | /** 36 | * 应用程序配置,包括配置拦截器,异常等; 37 | */ 38 | @Configuration 39 | public class AppWebMvcConfigurer implements WebMvcConfigurer { 40 | Logger logger = LoggerFactory.getLogger(AppWebMvcConfigurer.class); 41 | 42 | @Value("${privateKey}") 43 | String privateKey;//密钥,在配置文件 44 | @Value("${maxTimeGap}") 45 | Integer maxTimeGap;//验证签名,最大的时间差,在配置文件 46 | 47 | @Override 48 | public void addInterceptors(InterceptorRegistry registry) { 49 | //打印请求日志 50 | registry.addInterceptor(new HandlerInterceptor() { 51 | @Override 52 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { 53 | logger.info(getIpAddress(request) + "-" + request.getMethod() + "[" + request.getRequestURI() + "]"); 54 | return true; 55 | } 56 | }); 57 | // //添加签名验证 58 | // registry.addInterceptor(new HandlerInterceptor() { 59 | // @Override 60 | // public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { 61 | // if (!validateSign(request)) { 62 | // Result result = new Result(ResultCode.SIGN_FAIL, "[(" + request.getMethod() + ")" + request.getRequestURI() + "]非法请求"); 63 | // responseResult(response, result); 64 | // logger.warn(result.toString()); 65 | // return false; 66 | // } 67 | // return true; 68 | // } 69 | // }); 70 | } 71 | 72 | /** 73 | * 一个简单的签名认证,规则: 74 | * 1. 将请求参数按ascii码排序 75 | * 2. 拼接为a=value&b=value...这样的字符串(不包含sign) 76 | * 3. 混合密钥(secret)进行md5获得签名,与请求的签名进行比较 77 | */ 78 | private boolean validateSign(HttpServletRequest request) { 79 | String t = request.getHeader("t");//获得请求的时间戳 80 | if (StringUtils.isEmpty(t)) { 81 | return false; 82 | } 83 | long timestamp = Long.valueOf(t); 84 | if (Math.abs(System.currentTimeMillis() - timestamp) > maxTimeGap) { 85 | return false; 86 | } 87 | String requestSign = request.getHeader("sign");//获得请求签名,如sign=19e907700db7ad91318424a97c54ed57 88 | if (StringUtils.isEmpty(requestSign)) { 89 | return false; 90 | } 91 | List keys = new ArrayList(request.getParameterMap().keySet()); 92 | Collections.sort(keys);//排序 93 | StringBuilder sb = new StringBuilder(); 94 | for (String key : keys) { 95 | sb.append(key).append("=").append(request.getParameter(key)).append("&");//拼接字符串 96 | } 97 | if (sb.length() > 0) { 98 | sb.deleteCharAt(sb.length() - 1); 99 | } 100 | sb.append(privateKey); 101 | String sign = DigestUtils.md5DigestAsHex(sb.toString().getBytes());//混合密钥md5 102 | return requestSign.equals(sign); 103 | } 104 | 105 | @Override 106 | public void addCorsMappings(CorsRegistry registry) { 107 | //配置跨域请求 108 | registry.addMapping("/**") 109 | .allowedOrigins("*") 110 | .allowedHeaders("*") 111 | .allowCredentials(true) 112 | .allowedMethods("*"); 113 | } 114 | 115 | @Override 116 | public void configureHandlerExceptionResolvers(List resolvers) { 117 | resolvers.add((request, response, handler, ex) -> { 118 | Result result; 119 | if (ex instanceof BizException) { 120 | //业务异常,不需要打印堆栈 121 | result = new Result(((BizException) ex).getResultCode(), ex.getMessage()); 122 | responseResult(response, result); 123 | logger.warn(result.toString()); 124 | } else if (ex instanceof AppException) { 125 | //应用异常 126 | result = new Result(((AppException) ex).getResultCode(), ex.getMessage()); 127 | responseResult(response, result); 128 | logger.error(result.toString(), ex); 129 | } else if (ex instanceof NoHandlerFoundException || ex instanceof HttpRequestMethodNotSupportedException) { 130 | //不是服务器的异常,不需要打印堆栈 131 | result = new Result(ResultCode.NOT_FOUND, "接口[(" + request.getMethod() + ")" + request.getRequestURI() + "]不存在"); 132 | responseResult(response, result); 133 | logger.warn(result.toString()); 134 | } else if (ex instanceof BindException || ex instanceof MethodArgumentNotValidException) { 135 | //参数不合法 136 | List errors; 137 | if (ex instanceof BindException) { 138 | errors = ((BindException) ex).getAllErrors(); 139 | } else { 140 | errors = ((MethodArgumentNotValidException) ex).getBindingResult().getAllErrors(); 141 | } 142 | if (!errors.isEmpty()) { 143 | result = new Result(ResultCode.BIZ_FAIL, errors.get(0).getDefaultMessage()); 144 | } else { 145 | result = new Result(ResultCode.BIZ_FAIL, "数据验证错误"); 146 | } 147 | responseResult(response, result); 148 | logger.warn(result.toString()); 149 | } else if (ex instanceof ServletException) { 150 | result = new Result(ResultCode.INTERNAL_SERVER_ERROR, ex.getMessage()); 151 | responseResult(response, result); 152 | logger.error(result.toString(), ex); 153 | } else { 154 | //其他错误 155 | String message = String.format("接口 [%s] 出现异常,异常摘要:%s", request.getRequestURI(), ex.getMessage()); 156 | result = new Result(ResultCode.INTERNAL_SERVER_ERROR, message); 157 | responseResult(response, result); 158 | logger.error(result.toString(), ex); 159 | } 160 | return new ModelAndView(); 161 | }); 162 | } 163 | 164 | /** 165 | * 遇到错误,拦截以后输出响应到客户端 166 | */ 167 | private void responseResult(HttpServletResponse response, Result result) { 168 | response.setCharacterEncoding("UTF-8"); 169 | response.setHeader("Content-type", "application/json;charset=UTF-8"); 170 | response.setHeader("Access-Control-Allow-Credentials", "true"); 171 | response.setHeader("Access-Control-Allow-Origin", "*"); 172 | response.setStatus(200); 173 | try { 174 | ObjectMapper mapper = new ObjectMapper(); 175 | response.getWriter().write(mapper.writeValueAsString(result)); 176 | } catch (IOException ex) { 177 | logger.error(ex.getMessage()); 178 | } 179 | } 180 | 181 | /** 182 | * 获取客户端ip 183 | */ 184 | private String getIpAddress(HttpServletRequest request) { 185 | String ip = request.getHeader("x-forwarded-for"); 186 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 187 | ip = request.getHeader("Proxy-Client-IP"); 188 | } 189 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 190 | ip = request.getHeader("WL-Proxy-Client-IP"); 191 | } 192 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 193 | ip = request.getHeader("HTTP_CLIENT_IP"); 194 | } 195 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 196 | ip = request.getHeader("HTTP_X_FORWARDED_FOR"); 197 | } 198 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 199 | ip = request.getRemoteAddr(); 200 | } 201 | // 如果是多级代理,那么取第一个ip为客户端ip 202 | if (ip != null && ip.indexOf(",") != -1) { 203 | ip = ip.substring(0, ip.indexOf(",")).trim(); 204 | } 205 | return ip; 206 | } 207 | } 208 | -------------------------------------------------------------------------------- /BuildSrc/src/main/resources/java/JavaWebApplication.java: -------------------------------------------------------------------------------- 1 | package ${package}; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class JavaWebApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(JavaWebApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /BuildSrc/src/main/resources/java/Pagination.java: -------------------------------------------------------------------------------- 1 | package ${package}.base; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * 分页的数据结构 7 | */ 8 | public class Pagination { 9 | private Integer total; 10 | private Integer pageIndex; 11 | private List records; 12 | 13 | public Pagination(Integer total, Integer pageIndex, List records) { 14 | this.total = total; 15 | this.pageIndex = pageIndex; 16 | this.records = records; 17 | } 18 | 19 | public Integer getTotal() { 20 | return total; 21 | } 22 | 23 | public Pagination setTotal(Integer total) { 24 | this.total = total; 25 | return this; 26 | } 27 | 28 | public Integer getPageIndex() { 29 | return pageIndex; 30 | } 31 | 32 | public Pagination setPageIndex(Integer pageIndex) { 33 | this.pageIndex = pageIndex; 34 | return this; 35 | } 36 | 37 | public List getRecords() { 38 | return records; 39 | } 40 | 41 | public Pagination setRecords(List records) { 42 | this.records = records; 43 | return this; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /BuildSrc/src/main/resources/java/exception/AppException.java: -------------------------------------------------------------------------------- 1 | package ${package}.base.exception; 2 | 3 | import ${package}.base.result.ResultCode; 4 | 5 | /** 6 | * 应用程序异常异常,比如bug之类的,需要关注 7 | */ 8 | public class AppException extends RuntimeException { 9 | private ResultCode resultCode;//错误代码 10 | 11 | public AppException() { 12 | } 13 | 14 | public AppException(String message) { 15 | super(message); 16 | this.resultCode = ResultCode.INTERNAL_SERVER_ERROR; 17 | } 18 | 19 | public ResultCode getResultCode() { 20 | return resultCode; 21 | } 22 | 23 | public void setCode(ResultCode code) { 24 | this.resultCode = code; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /BuildSrc/src/main/resources/java/exception/BizException.java: -------------------------------------------------------------------------------- 1 | package ${package}.base.exception; 2 | 3 | import ${package}.base.result.ResultCode; 4 | 5 | /** 6 | * 业务异常,一般不是应用的错误,比如:用户登陆没有输入账号 7 | */ 8 | public class BizException extends RuntimeException { 9 | private ResultCode resultCode;//错误代码 10 | 11 | public BizException() { 12 | } 13 | 14 | public BizException(String message) { 15 | super(message); 16 | this.resultCode = ResultCode.BIZ_FAIL; 17 | } 18 | 19 | public ResultCode getResultCode() { 20 | return resultCode; 21 | } 22 | 23 | public void setCode(ResultCode code) { 24 | this.resultCode = code; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /BuildSrc/src/main/resources/java/result/Result.java: -------------------------------------------------------------------------------- 1 | package ${package}.base.result; 2 | 3 | /** 4 | * 返回结果数据结构 5 | */ 6 | public class Result { 7 | private Integer code; 8 | private String msg; 9 | private T data; 10 | 11 | public Result(ResultCode code, String msg, T data) { 12 | this.code = code.getCode(); 13 | this.msg = msg; 14 | this.data = data; 15 | } 16 | 17 | public Result(ResultCode code, String msg) { 18 | this.code = code.getCode(); 19 | this.msg = msg; 20 | } 21 | 22 | public static Result getSuccess(T data) { 23 | return new Result(ResultCode.SUCCESS, "处理成功", data); 24 | } 25 | 26 | public static Result getBizFail(String msg) { 27 | return new Result(ResultCode.BIZ_FAIL, msg); 28 | } 29 | 30 | public Integer getCode() { 31 | return code; 32 | } 33 | 34 | 35 | public String getMsg() { 36 | return msg; 37 | } 38 | 39 | public T getData() { 40 | return data; 41 | } 42 | 43 | @Override 44 | public String toString() { 45 | return "[" + getCode() + "]" + getMsg(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /BuildSrc/src/main/resources/java/result/ResultCode.java: -------------------------------------------------------------------------------- 1 | package ${package}.base.result; 2 | 3 | /** 4 | * 返回编码,参考http语义 5 | */ 6 | public enum ResultCode { 7 | SUCCESS(200),//成功 8 | BIZ_FAIL(400),//业务异常错误 9 | UNAUTHORIZED(401),//未认证 10 | SIGN_FAIL(402),//签名错误 11 | NOT_FOUND(404),//接口不存在 12 | INTERNAL_SERVER_ERROR(500);//服务器内部错误 13 | 14 | private final int code; 15 | 16 | ResultCode(int code) { 17 | this.code = code; 18 | } 19 | 20 | public int getCode() { 21 | return code; 22 | } 23 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /TestGradlePlugin/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'javaweb-api-generate' 2 | 3 | config { 4 | dbDriver 'com.mysql.jdbc.Driver' 5 | dbHost '127.0.0.1' 6 | dbPort '3306' 7 | dbName 'pangu-db-dev' 8 | dbUser 'root' 9 | dbPassword '123456' 10 | basePackage 'com.zjiecode.java.api' 11 | } 12 | 13 | //以上是生成的配置信息,生成以后可以删除 14 | buildscript { 15 | repositories { 16 | // 使用本地仓库调试 17 | // maven{ 18 | // url uri("../repo") 19 | // } 20 | jcenter() 21 | mavenCentral() 22 | } 23 | dependencies { 24 | classpath "org.springframework.boot:spring-boot-gradle-plugin:2.0.1.RELEASE" 25 | // classpath 'com.zjiecode:javaweb-api-generate:0.0.14'//生成代码用的插件,生成代码以后可以删除 26 | } 27 | } 28 | 29 | apply plugin: 'java' 30 | apply plugin: 'idea' 31 | apply plugin: 'org.springframework.boot' 32 | apply plugin: 'io.spring.dependency-management' 33 | 34 | repositories { 35 | 36 | jcenter() 37 | mavenCentral() 38 | } 39 | 40 | dependencies { 41 | compile('org.springframework.boot:spring-boot-starter-validation') 42 | compile('org.springframework.boot:spring-boot-starter-web') 43 | compile('org.mybatis.spring.boot:mybatis-spring-boot-starter:1.3.2') 44 | compile('mysql:mysql-connector-java:5.1.44') 45 | compile('javax.persistence:persistence-api:1.0') 46 | } 47 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zjiecode/javaweb-api-generate/e5112ac3985a5b5025fde4e7b68e45ce452e8d87/build.gradle -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zjiecode/javaweb-api-generate/e5112ac3985a5b5025fde4e7b68e45ce452e8d87/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sat Apr 21 23:58:00 CST 2018 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.5.1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn ( ) { 37 | echo "$*" 38 | } 39 | 40 | die ( ) { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save ( ) { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /publish.sh: -------------------------------------------------------------------------------- 1 | echo '请输入bintrayKey:' 2 | read bintrayKey 3 | ./gradlew clean build bintrayUpload -PbintrayUser=zjiecode -PbintrayKey=$bintrayKey -PdryRun=false -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ## javaweb-api-generate 2 | 3 | ![author](https://img.shields.io/badge/author-zjiecode-green.svg?longCache=true&style=flat) 4 | ![star](https://img.shields.io/redmine/plugin/stars/redmine_xlsx_format_issue_exporter.svg) 5 | ![language](https://img.shields.io/badge/language-java-blue.svg) 6 | ![PRs-welcome](https://img.shields.io/badge/PRs-welcome-green.svg?longCache=true&style=flat) 7 | [![license](https://img.shields.io/hexpm/l/plug.svg)](http://www.apache.org/licenses/LICENSE-2.0) 8 | [![Build Status](https://travis-ci.org/zjiecode/javaweb-api-generate.svg?branch=master)](https://travis-ci.org/zjiecode/javaweb-api-generate) 9 | ![version](https://img.shields.io/badge/version-0.0.14-brightgreen.svg?longCache=true&style=flat) 10 | 11 | ### 简介 12 | 13 | 很多时候,想要开发一个小玩意儿,核心功能开发本来就很累了(尤其是对于个人开发者)但还要开发一个后台,针对增删改查的简单后台,写起来更累。 14 | 使用这个gradle插件,能够非常快的根据你设计的数据库,生成一个对应的api接口的网站。然后稍微修改一下, 15 | 基本就可以完成一个信息的增删改查系统了。 16 | 17 | ### 生成的代码的环境 18 | 19 | 本插件的环境: 20 | - 推荐使用IDE:`idea`; 21 | - 构建工具:`gradle`; 22 | - 网站使用框架:`spring boot`; 23 | - 使用的数据:`mysql` 24 | ### 原理 25 | 26 | 插件根据你输入的数据库,读取对应的数据库结构,生成对应的表的接口代码 27 | 28 | ### 使用方式 29 | #### mac/linux 30 | 打开终端,复制下面代码直接执行,根据中文提示,输入对应的信息即可。 31 | ```shell 32 | bash <(curl -s -S -L https://github.com/zjiecode/javaweb-api-generate/raw/master/setup/setup.sh) 33 | ``` 34 | #### windows 35 | - 点击这里[https://github.com/zjiecode/javaweb-api-generate/raw/master/setup/template.zip](https://github.com/zjiecode/javaweb-api-generate/raw/master/setup/template.zip),下载模版, 36 | - 解压下载下来的zip包; 37 | - 修改`builde.gradle`里面的配置信息 38 | ```groovy 39 | config { 40 | dbDriver 'com.mysql.jdbc.Driver' 41 | dbHost '127.0.0.1' 42 | dbPort '3306' 43 | dbName 'spring_boot_demo' 44 | dbUser 'root' 45 | dbPassword '123456' 46 | basePackage 'com.zjiecode.web.api' 47 | } 48 | ``` 49 | - 执行`gradlew.bat generateCode` 50 | - 如果生成成功,执行`gradlew.bat bootRun` 就可以启动网站了 51 | 52 | 如果不出意外 ,就生成了网站工程,在你解压的zip包里面,直接用idea打开就可以了。 53 | 54 | #### 给已有项目添加插件 55 | 56 | - 添加插件依赖 57 | ```groovy 58 | classpath 'com.zjiecode:javaweb-api-generate:{last-version}'//把last-version替换成最新版本 59 | ``` 60 | - 添加应用插件 61 | ```groovy 62 | apply plugin: 'javaweb-api-generate'//生成代码用的插件 63 | ``` 64 | - 设置配置信息 65 | ```groovy 66 | config { 67 | dbDriver 'com.mysql.jdbc.Driver' 68 | dbHost '127.0.0.1' 69 | dbPort '3306' 70 | dbName 'spring_boot_demo' 71 | dbUser 'root' 72 | dbPassword '123456' 73 | basePackage 'com.zjiecode.web.api' 74 | } 75 | ``` 76 | 77 | 到这里,就添加完了插件,刷新一下gradle,你会看到多出来一个`generateCode`任务,运行就可以了。 78 | 79 | **【注意】生成后,请删除本插件,不然,重复生成,会覆盖掉你修改的代码** 80 | 81 | ### 生成的网站工程介绍 82 | 83 | #### 接口 84 | 会生成每个数据库表对应的接口,每个表会对应生成7个接口,分别如下 85 | 86 | 【post】 /{表名}/ 插入数据; 87 | 【put】 /{表名}/{id} 修改数据; 88 | 【delete】/{表名}/{id} 删除数据; 89 | 【get】 /{表名}/{id} 查询某一条数据; 90 | 【get】 /{表名}/{pageIndex}/{pageSize} 分页查询; 91 | 【get】 /{表名}/all 查询全部数据; 92 | 【get】 /{表名}/count} 查询数据条数; 93 | 94 | **生成以后,也就意味可以直接访问数据库所有数据,请务必删除不需要的接口。** 95 | 96 | #### 接口数据结构 97 | ```js 98 | { 99 | code: 402, //状态 100 | msg: "[(GET)/user/2]非法请求", //提示信息 101 | data: null //数据 102 | } 103 | ``` 104 | 105 | #### 错误拦截 106 | 107 | 错误均已经拦截, 返回json格式数据 108 | 109 | SUCCESS(200),//成功 110 | BIZ_FAIL(400),//业务异常错误 111 | UNAUTHORIZED(401),//未认证 112 | SIGN_FAIL(402),//签名错误 113 | NOT_FOUND(404),//接口不存在 114 | INTERNAL_SERVER_ERROR(500);//服务器内部错误 115 | 116 | #### 接口签名验证 117 | 118 | 为了保证接口安全 ,避免被非法调用,添加了简单的数据签名,获取所有的参数,按照字典排序,加入密钥和时间戳,做MD5运算, 119 | 服务器验证时间差距太大,或者签名不正确会拒绝请求。 120 | 签名相关的密约,可以在`application.properties`文件中配置; 121 | 122 | 签名相关实现,请查看`AppWebMvcConfigurer`类。 123 | 124 | #### 请求方式(数据格式) 125 | 默认的post提交数据方式是:x-www-form-urlencoded,也就是采用a-1&b=2这种 126 | 如果你使用json的方式提交数据,可以在字段上注解@ResquestBody即可。 127 | 128 | ### Pull Request 129 | 任何问题,欢迎PR,PR请提交到`develop`分支,感谢. 130 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'javaWebApi' 2 | include 'BuildSrc','TestGradlePlugin' 3 | 4 | -------------------------------------------------------------------------------- /setup/setup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | echo "获取构建脚本成功" 4 | 5 | tempFileName="template.zip" 6 | 7 | echo "请输入工程名字:" 8 | read project 9 | 10 | if [ -d "${project}" ]; then 11 | echo "${project}已经存在,是否删除(y/n)?" 12 | read del 13 | if [ "${del}" == "y" ]; then 14 | rm -rf "${project}" 15 | else 16 | exit 1 17 | fi 18 | fi 19 | 20 | if [ ! -f "${tempFileName}" ]; then 21 | echo "下载资源文件,请稍后" 22 | result=`curl -s "https://raw.githubusercontent.com/zjiecode/javaweb-api-generate/master/setup/template.zip" --output "${tempFileName}"` 23 | fi 24 | 25 | if [ ! -f "${tempFileName}" ]; then 26 | echo "下载资源文件失败,请重试" 27 | exit 1 28 | fi 29 | 30 | #解压模版压缩包 31 | unzip "${tempFileName}" -d "${project}" 32 | if [ $? -ne 0 ];then 33 | echo "解压错误" 34 | exit 1 35 | fi 36 | 37 | echo "解压模版完成" 38 | 39 | cd "${project}" 40 | 41 | #调用生成的脚本 42 | 43 | PROPERTY_FILE="build.gradle" #配置文件 44 | 45 | echo "请输入数据库地址和端口(127.0.0.1):" 46 | read dbHost 47 | if [ -z "${dbHost}" ]; then 48 | dbHost="127.0.0.1" 49 | fi 50 | echo "请输入数据库地址和端口(3306):" 51 | read dbPort 52 | if [ -z "${dbPort}" ]; then 53 | dbPort="3306" 54 | fi 55 | echo "请输入数据库名字:" 56 | read dbName 57 | if [ -z "${dbName}" ]; then 58 | echo "数据库名字不能为空" 59 | exit 1; 60 | fi 61 | echo "请输入数据库登陆用户名:" 62 | read dbUser 63 | if [ -z "${dbUser}" ]; then 64 | echo "数据库用户名不能为空" 65 | exit 1; 66 | fi 67 | 68 | echo "请输入数据库登陆用户密码:" 69 | read dbPassword 70 | if [ -z "${dbPassword}" ]; then 71 | echo "数据库密码不能为空" 72 | exit 1; 73 | fi 74 | echo "请输入生成代码包名:" 75 | read basePackage 76 | if [ -z "${basePackage}" ]; then 77 | echo "基础包名不能为空" 78 | exit 1; 79 | fi 80 | 81 | # 设置值,key,value 82 | function setValue(){ 83 | PROPERTY_LINE=`grep $1 ${PROPERTY_FILE}` 84 | if [ -z "${PROPERTY_LINE}" ]; then 85 | echo "配置文件 ${PROPERTY_FILE} 中不存在属性 $1" 86 | exit 1 87 | else 88 | NEW_PROPERTY_LINE="\t$1 '$2'" 89 | sed -i -e "s/${PROPERTY_LINE}/${NEW_PROPERTY_LINE}/" ${PROPERTY_FILE} 90 | fi 91 | } 92 | echo "正在配置文件..." 93 | 94 | setValue "dbHost" "${dbHost}" 95 | setValue "dbPort" "${dbPort}" 96 | setValue "dbName" "${dbName}" 97 | setValue "dbPassword" "${dbPassword}" 98 | setValue "dbUser" "${dbUser}" 99 | setValue "basePackage" "${basePackage}" 100 | 101 | echo "配置文件完成" 102 | 103 | # 替换gradle配置 104 | echo "开始生成代码" 105 | ./gradlew generateCode 106 | echo "生成完毕" 107 | 108 | 109 | if [ $? -ne 0 ];then 110 | echo "生成错误" 111 | cd .. 112 | rm -rf "${project}" 113 | exit 1 114 | fi 115 | 116 | path=`pwd` 117 | cd .. 118 | echo "清理资源" 119 | rm "${tempFileName}" 120 | rm setup.sh 121 | 122 | echo "\033[32m SUCCESS \033[0m" 123 | echo "工程地址:${path}" 124 | echo "你启动工程或者使用IDEA打开它" 125 | echo "linux/mac启动命令: ./gradlew bootRun" 126 | echo "window启动命令: gradle.bat bootRun" 127 | echo "访问地址:http://127.0.0.1:8080/" 128 | -------------------------------------------------------------------------------- /setup/template.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zjiecode/javaweb-api-generate/e5112ac3985a5b5025fde4e7b68e45ce452e8d87/setup/template.zip --------------------------------------------------------------------------------