├── .gitignore ├── README.md ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── company │ │ └── project │ │ ├── Application.java │ │ ├── configurer │ │ ├── MybatisConfigurer.java │ │ └── WebMvcConfigurer.java │ │ └── core │ │ ├── AbstractService.java │ │ ├── Mapper.java │ │ ├── ProjectConstant.java │ │ ├── Result.java │ │ ├── ResultCode.java │ │ ├── ResultGenerator.java │ │ ├── Service.java │ │ └── ServiceException.java └── resources │ ├── application-dev.properties │ ├── application-prod.properties │ ├── application-test.properties │ ├── application.properties │ └── banner.txt └── test ├── java ├── CodeGenerator.java └── com │ └── conpany │ └── project │ └── Tester.java └── resources ├── demo-user.sql └── generator └── template ├── controller-restful.ftl ├── controller.ftl ├── service-impl.ftl └── service.ftl /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | 3 | ### STS ### 4 | .apt_generated 5 | .classpath 6 | .factorypath 7 | .project 8 | .settings 9 | .springBeans 10 | 11 | ### IntelliJ IDEA ### 12 | .idea 13 | *.iws 14 | *.iml 15 | *.ipr 16 | 17 | ### NetBeans ### 18 | nbproject/private/ 19 | build/ 20 | nbbuild/ 21 | dist/ 22 | nbdist/ 23 | .nb-gradle/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Licence](https://img.shields.io/badge/licence-none-green.svg) 2 | [![GitHub Release](https://img.shields.io/github/release/lihengming/spring-boot-api-project-seed.svg)](https://github.com/lihengming/spring-boot-api-project-seed/releases) 3 | ## 简介 4 | Spring Boot API Project Seed 是一个基于Spring Boot & MyBatis的种子项目,用于快速构建中小型API、RESTful API项目,该种子项目已经有过多个真实项目的实践,稳定、简单、快速,使我们摆脱那些重复劳动,专注于业务代码的编写,减少加班。下面是一个简单的使用演示,看如何基于本项目在短短几十秒钟内实现一套简单的API,并运行提供服务。 5 | 6 | [![请选择超清](https://raw.githubusercontent.com/lihengming/java-codes/master/shared-resources/github-images/project-example-youku.png)](http://v.youku.com/v_show/id_XMjg1NjYwNDgxNg==.html?spm=a2h3j.8428770.3416059.1) 7 | ## 特征&提供 8 | - 最佳实践的项目结构、配置文件、精简的POM([查看项目结构图](https://github.com/lihengming/java-codes/blob/master/shared-resources/github-images/project-struct.png)) 9 | - 统一响应结果封装及生成工具 10 | - 统一异常处理 11 | - 简单的接口签名认证 12 | - 常用基础方法抽象封装 13 | - 使用Druid Spring Boot Starter 集成Druid数据库连接池与监控 14 | - 使用FastJsonHttpMessageConverter,提高JSON序列化速度 15 | - 集成MyBatis、通用Mapper插件、PageHelper分页插件,实现单表业务零SQL 16 | - 提供代码生成器根据表名生成对应的Model、Mapper、MapperXML、Service、ServiceImpl、Controller等基础代码,其中Controller模板默认提供POST和RESTful两套,根据需求在```CodeGenerator.genController(tableName)```方法中自己选择,默认使用POST模板。代码模板可根据实际项目的需求来扩展,由于每个公司业务都不太一样,所以只提供了一些比较基础、通用的模板,**主要是提供一个思路**来减少重复代码的编写,我在实际项目的使用中,其实根据公司业务的抽象编写了大量的模板。另外,使用模板也有助于保持团队代码风格的统一 17 | - 另有彩蛋,待你探索 18 |   19 | ## 快速开始 20 | 1. 克隆项目 21 | 2. 对```test```包内的代码生成器```CodeGenerator```进行配置,主要是JDBC,因为要根据表名来生成代码 22 | 3. 如果只是想根据上面的演示来亲自试试的话可以使用```test resources```目录下的```demo-user.sql```,否则忽略该步 23 | 3. 输入表名,运行```CodeGenerator.main()```方法,生成基础代码(可能需要刷新项目目录才会出来) 24 | 4. 根据业务在基础代码上进行扩展 25 | 5. 对开发环境配置文件```application-dev.properties```进行配置,启动项目,Have Fun! 26 |   27 | ## 开发建议 28 | - 表名,建议使用小写,多个单词使用下划线拼接 29 | - Model内成员变量建议与表字段数量对应,如需扩展成员变量(比如连表查询)建议创建DTO,否则需在扩展的成员变量上加```@Transient```注解,详情见[通用Mapper插件文档说明](https://mapperhelper.github.io/docs/2.use/) 30 | - 建议业务失败直接使用```ServiceException("message")```抛出,由统一异常处理器来封装业务失败的响应结果,比如```throw new ServiceException("该手机号已被注册")```,会直接被封装为```{"code":400,"message":"该手机号已被注册"}```返回,无需自己处理,尽情抛出 31 | - 需要工具类的话建议先从```apache-commons-*```和```guava```中找,实在没有再造轮子或引入类库,尽量精简项目 32 | - 开发规范建议遵循阿里巴巴Java开发手册([最新版下载](https://github.com/alibaba/p3c)) 33 | - 建议在公司内部使用[ShowDoc](https://github.com/star7th/showdoc)、[SpringFox-Swagger2](https://github.com/springfox/springfox) 、[RAP](https://github.com/thx/RAP)等开源项目来编写、管理API文档 34 |   35 | ## 技术选型&文档 36 | - Spring Boot([查看Spring Boot学习&使用指南](http://www.jianshu.com/p/1a9fd8936bd8)) 37 | - MyBatis([查看官方中文文档](http://www.mybatis.org/mybatis-3/zh/index.html)) 38 | - MyBatisb通用Mapper插件([查看官方中文文档](https://mapperhelper.github.io/docs/)) 39 | - MyBatis PageHelper分页插件([查看官方中文文档](https://pagehelper.github.io/)) 40 | - Druid Spring Boot Starter([查看官方中文文档](https://github.com/alibaba/druid/tree/master/druid-spring-boot-starter/)) 41 | - Fastjson([查看官方中文文档](https://github.com/Alibaba/fastjson/wiki/%E9%A6%96%E9%A1%B5)) 42 | - 其他略 43 | 44 | ## License 45 | 无,纯粹开源分享,感谢大家 [Star](https://github.com/lihengming/spring-boot-api-project-seed/stargazers) & [Fork](https://github.com/lihengming/spring-boot-api-project-seed/network/members) 的支持。 46 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.github.lihengming 8 | spring-boot-api-project-seed 9 | 1.0 10 | jar 11 | 12 | 13 | 1.8 14 | 15 | 16 | 17 | 18 | org.springframework.boot 19 | spring-boot-starter-parent 20 | 1.5.13.RELEASE 21 | 22 | 23 | 24 | 25 | 26 | org.springframework.boot 27 | spring-boot-starter-web 28 | 29 | 30 | org.springframework.boot 31 | spring-boot-starter-jdbc 32 | 33 | 34 | org.springframework.boot 35 | spring-boot-starter-test 36 | test 37 | 38 | 39 | 40 | commons-codec 41 | commons-codec 42 | 43 | 44 | org.apache.commons 45 | commons-lang3 46 | 3.6 47 | 48 | 49 | com.google.guava 50 | guava 51 | 23.0 52 | 53 | 54 | 55 | mysql 56 | mysql-connector-java 57 | runtime 58 | 59 | 60 | 61 | org.mybatis 62 | mybatis-spring 63 | 1.3.1 64 | 65 | 66 | org.mybatis 67 | mybatis 68 | 3.4.5 69 | 70 | 71 | tk.mybatis 72 | mapper 73 | 3.4.2 74 | 75 | 76 | com.github.pagehelper 77 | pagehelper 78 | 4.2.1 79 | 80 | 81 | 82 | com.alibaba 83 | fastjson 84 | 1.2.47 85 | 86 | 87 | 88 | com.alibaba 89 | druid-spring-boot-starter 90 | 1.1.10 91 | 92 | 93 | 94 | org.freemarker 95 | freemarker 96 | 2.3.23 97 | test 98 | 99 | 100 | org.mybatis.generator 101 | mybatis-generator-core 102 | 1.3.5 103 | test 104 | 105 | 106 | 107 | 108 | 109 | 110 | org.springframework.boot 111 | spring-boot-maven-plugin 112 | 113 | 114 | maven-compiler-plugin 115 | 116 | ${java.version} 117 | ${java.version} 118 | UTF-8 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | aliyun-repos 127 | http://maven.aliyun.com/nexus/content/groups/public/ 128 | 129 | false 130 | 131 | 132 | 133 | 134 | 135 | 136 | aliyun-plugin 137 | http://maven.aliyun.com/nexus/content/groups/public/ 138 | 139 | false 140 | 141 | 142 | 143 | 144 | -------------------------------------------------------------------------------- /src/main/java/com/company/project/Application.java: -------------------------------------------------------------------------------- 1 | package com.company.project; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class Application { 8 | public static void main(String[] args) { 9 | SpringApplication.run(Application.class, args); 10 | } 11 | } 12 | 13 | -------------------------------------------------------------------------------- /src/main/java/com/company/project/configurer/MybatisConfigurer.java: -------------------------------------------------------------------------------- 1 | package com.company.project.configurer; 2 | 3 | import com.github.pagehelper.PageHelper; 4 | import org.apache.ibatis.plugin.Interceptor; 5 | import org.apache.ibatis.session.SqlSessionFactory; 6 | import org.mybatis.spring.SqlSessionFactoryBean; 7 | import org.springframework.beans.factory.annotation.Qualifier; 8 | import org.springframework.boot.autoconfigure.AutoConfigureAfter; 9 | import org.springframework.context.annotation.Bean; 10 | import org.springframework.context.annotation.Conditional; 11 | import org.springframework.context.annotation.Configuration; 12 | import org.springframework.core.io.support.PathMatchingResourcePatternResolver; 13 | import org.springframework.core.io.support.ResourcePatternResolver; 14 | import tk.mybatis.spring.mapper.MapperScannerConfigurer; 15 | 16 | import javax.annotation.Resource; 17 | import javax.sql.DataSource; 18 | import java.util.Properties; 19 | 20 | import static com.company.project.core.ProjectConstant.*; 21 | 22 | /** 23 | * Mybatis & Mapper & PageHelper 配置 24 | */ 25 | @Configuration 26 | public class MybatisConfigurer { 27 | 28 | @Bean 29 | public SqlSessionFactory sqlSessionFactoryBean(DataSource dataSource) throws Exception { 30 | SqlSessionFactoryBean factory = new SqlSessionFactoryBean(); 31 | factory.setDataSource(dataSource); 32 | factory.setTypeAliasesPackage(MODEL_PACKAGE); 33 | 34 | //配置分页插件,详情请查阅官方文档 35 | PageHelper pageHelper = new PageHelper(); 36 | Properties properties = new Properties(); 37 | properties.setProperty("pageSizeZero", "true");//分页尺寸为0时查询所有纪录不再执行分页 38 | properties.setProperty("reasonable", "true");//页码<=0 查询第一页,页码>=总页数查询最后一页 39 | properties.setProperty("supportMethodsArguments", "true");//支持通过 Mapper 接口参数来传递分页参数 40 | pageHelper.setProperties(properties); 41 | 42 | //添加插件 43 | factory.setPlugins(new Interceptor[]{pageHelper}); 44 | 45 | //添加XML目录 46 | ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); 47 | factory.setMapperLocations(resolver.getResources("classpath:mapper/*.xml")); 48 | return factory.getObject(); 49 | } 50 | 51 | @Bean 52 | public MapperScannerConfigurer mapperScannerConfigurer() { 53 | MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer(); 54 | mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactoryBean"); 55 | mapperScannerConfigurer.setBasePackage(MAPPER_PACKAGE); 56 | 57 | //配置通用Mapper,详情请查阅官方文档 58 | Properties properties = new Properties(); 59 | properties.setProperty("mappers", MAPPER_INTERFACE_REFERENCE); 60 | properties.setProperty("notEmpty", "false");//insert、update是否判断字符串类型!='' 即 test="str != null"表达式内是否追加 and str != '' 61 | properties.setProperty("IDENTITY", "MYSQL"); 62 | mapperScannerConfigurer.setProperties(properties); 63 | 64 | return mapperScannerConfigurer; 65 | } 66 | 67 | } 68 | 69 | -------------------------------------------------------------------------------- /src/main/java/com/company/project/configurer/WebMvcConfigurer.java: -------------------------------------------------------------------------------- 1 | package com.company.project.configurer; 2 | 3 | import java.io.IOException; 4 | import java.nio.charset.Charset; 5 | import java.util.ArrayList; 6 | import java.util.Arrays; 7 | import java.util.Collections; 8 | import java.util.List; 9 | 10 | import javax.servlet.ServletException; 11 | import javax.servlet.http.HttpServletRequest; 12 | import javax.servlet.http.HttpServletResponse; 13 | 14 | import com.alibaba.fastjson.JSON; 15 | import com.alibaba.fastjson.serializer.SerializerFeature; 16 | import com.alibaba.fastjson.support.config.FastJsonConfig; 17 | import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter; 18 | 19 | import com.company.project.core.Result; 20 | import com.company.project.core.ResultCode; 21 | import com.company.project.core.ServiceException; 22 | import org.apache.commons.codec.digest.DigestUtils; 23 | import org.apache.commons.lang3.StringUtils; 24 | import org.slf4j.Logger; 25 | import org.slf4j.LoggerFactory; 26 | import org.springframework.beans.factory.annotation.Value; 27 | import org.springframework.context.annotation.Configuration; 28 | import org.springframework.http.MediaType; 29 | import org.springframework.http.converter.HttpMessageConverter; 30 | import org.springframework.web.method.HandlerMethod; 31 | import org.springframework.web.servlet.HandlerExceptionResolver; 32 | import org.springframework.web.servlet.ModelAndView; 33 | import org.springframework.web.servlet.NoHandlerFoundException; 34 | import org.springframework.web.servlet.config.annotation.CorsRegistry; 35 | import org.springframework.web.servlet.config.annotation.InterceptorRegistry; 36 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; 37 | import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; 38 | 39 | /** 40 | * Spring MVC 配置 41 | */ 42 | @Configuration 43 | public class WebMvcConfigurer extends WebMvcConfigurerAdapter { 44 | 45 | private final Logger logger = LoggerFactory.getLogger(WebMvcConfigurer.class); 46 | @Value("${spring.profiles.active}") 47 | private String env;//当前激活的配置文件 48 | 49 | //使用阿里 FastJson 作为JSON MessageConverter 50 | @Override 51 | public void configureMessageConverters(List> converters) { 52 | FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter(); 53 | FastJsonConfig config = new FastJsonConfig(); 54 | config.setSerializerFeatures(SerializerFeature.WriteMapNullValue);//保留空的字段 55 | //SerializerFeature.WriteNullStringAsEmpty,//String null -> "" 56 | //SerializerFeature.WriteNullNumberAsZero//Number null -> 0 57 | // 按需配置,更多参考FastJson文档哈 58 | 59 | converter.setFastJsonConfig(config); 60 | converter.setDefaultCharset(Charset.forName("UTF-8")); 61 | converter.setSupportedMediaTypes(Arrays.asList(MediaType.APPLICATION_JSON_UTF8)); 62 | converters.add(converter); 63 | } 64 | 65 | 66 | //统一异常处理 67 | @Override 68 | public void configureHandlerExceptionResolvers(List exceptionResolvers) { 69 | exceptionResolvers.add(new HandlerExceptionResolver() { 70 | public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception e) { 71 | Result result = new Result(); 72 | if (e instanceof ServiceException) {//业务失败的异常,如“账号或密码错误” 73 | result.setCode(ResultCode.FAIL).setMessage(e.getMessage()); 74 | logger.info(e.getMessage()); 75 | } else if (e instanceof NoHandlerFoundException) { 76 | result.setCode(ResultCode.NOT_FOUND).setMessage("接口 [" + request.getRequestURI() + "] 不存在"); 77 | } else if (e instanceof ServletException) { 78 | result.setCode(ResultCode.FAIL).setMessage(e.getMessage()); 79 | } else { 80 | result.setCode(ResultCode.INTERNAL_SERVER_ERROR).setMessage("接口 [" + request.getRequestURI() + "] 内部错误,请联系管理员"); 81 | String message; 82 | if (handler instanceof HandlerMethod) { 83 | HandlerMethod handlerMethod = (HandlerMethod) handler; 84 | message = String.format("接口 [%s] 出现异常,方法:%s.%s,异常摘要:%s", 85 | request.getRequestURI(), 86 | handlerMethod.getBean().getClass().getName(), 87 | handlerMethod.getMethod().getName(), 88 | e.getMessage()); 89 | } else { 90 | message = e.getMessage(); 91 | } 92 | logger.error(message, e); 93 | } 94 | responseResult(response, result); 95 | return new ModelAndView(); 96 | } 97 | 98 | }); 99 | } 100 | 101 | //解决跨域问题 102 | @Override 103 | public void addCorsMappings(CorsRegistry registry) { 104 | //registry.addMapping("/**"); 105 | } 106 | 107 | //添加拦截器 108 | @Override 109 | public void addInterceptors(InterceptorRegistry registry) { 110 | //接口签名认证拦截器,该签名认证比较简单,实际项目中可以使用Json Web Token或其他更好的方式替代。 111 | if (!"dev".equals(env)) { //开发环境忽略签名认证 112 | registry.addInterceptor(new HandlerInterceptorAdapter() { 113 | @Override 114 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { 115 | //验证签名 116 | boolean pass = validateSign(request); 117 | if (pass) { 118 | return true; 119 | } else { 120 | logger.warn("签名认证失败,请求接口:{},请求IP:{},请求参数:{}", 121 | request.getRequestURI(), getIpAddress(request), JSON.toJSONString(request.getParameterMap())); 122 | 123 | Result result = new Result(); 124 | result.setCode(ResultCode.UNAUTHORIZED).setMessage("签名认证失败"); 125 | responseResult(response, result); 126 | return false; 127 | } 128 | } 129 | }); 130 | } 131 | } 132 | 133 | private void responseResult(HttpServletResponse response, Result result) { 134 | response.setCharacterEncoding("UTF-8"); 135 | response.setHeader("Content-type", "application/json;charset=UTF-8"); 136 | response.setStatus(200); 137 | try { 138 | response.getWriter().write(JSON.toJSONString(result)); 139 | } catch (IOException ex) { 140 | logger.error(ex.getMessage()); 141 | } 142 | } 143 | 144 | /** 145 | * 一个简单的签名认证,规则: 146 | * 1. 将请求参数按ascii码排序 147 | * 2. 拼接为a=value&b=value...这样的字符串(不包含sign) 148 | * 3. 混合密钥(secret)进行md5获得签名,与请求的签名进行比较 149 | */ 150 | private boolean validateSign(HttpServletRequest request) { 151 | String requestSign = request.getParameter("sign");//获得请求签名,如sign=19e907700db7ad91318424a97c54ed57 152 | if (StringUtils.isEmpty(requestSign)) { 153 | return false; 154 | } 155 | List keys = new ArrayList(request.getParameterMap().keySet()); 156 | keys.remove("sign");//排除sign参数 157 | Collections.sort(keys);//排序 158 | 159 | StringBuilder sb = new StringBuilder(); 160 | for (String key : keys) { 161 | sb.append(key).append("=").append(request.getParameter(key)).append("&");//拼接字符串 162 | } 163 | String linkString = sb.toString(); 164 | linkString = StringUtils.substring(linkString, 0, linkString.length() - 1);//去除最后一个'&' 165 | 166 | String secret = "Potato";//密钥,自己修改 167 | String sign = DigestUtils.md5Hex(linkString + secret);//混合密钥md5 168 | 169 | return StringUtils.equals(sign, requestSign);//比较 170 | } 171 | 172 | private String getIpAddress(HttpServletRequest request) { 173 | String ip = request.getHeader("x-forwarded-for"); 174 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 175 | ip = request.getHeader("Proxy-Client-IP"); 176 | } 177 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 178 | ip = request.getHeader("WL-Proxy-Client-IP"); 179 | } 180 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 181 | ip = request.getHeader("HTTP_CLIENT_IP"); 182 | } 183 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 184 | ip = request.getHeader("HTTP_X_FORWARDED_FOR"); 185 | } 186 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 187 | ip = request.getRemoteAddr(); 188 | } 189 | // 如果是多级代理,那么取第一个ip为客户端ip 190 | if (ip != null && ip.indexOf(",") != -1) { 191 | ip = ip.substring(0, ip.indexOf(",")).trim(); 192 | } 193 | 194 | return ip; 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /src/main/java/com/company/project/core/AbstractService.java: -------------------------------------------------------------------------------- 1 | package com.company.project.core; 2 | 3 | 4 | import org.apache.ibatis.exceptions.TooManyResultsException; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import tk.mybatis.mapper.entity.Condition; 7 | 8 | import java.lang.reflect.Field; 9 | import java.lang.reflect.ParameterizedType; 10 | import java.util.List; 11 | 12 | /** 13 | * 基于通用MyBatis Mapper插件的Service接口的实现 14 | */ 15 | public abstract class AbstractService implements Service { 16 | 17 | @Autowired 18 | protected Mapper mapper; 19 | 20 | private Class modelClass; // 当前泛型真实类型的Class 21 | 22 | public AbstractService() { 23 | ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass(); 24 | modelClass = (Class) pt.getActualTypeArguments()[0]; 25 | } 26 | 27 | public void save(T model) { 28 | mapper.insertSelective(model); 29 | } 30 | 31 | public void save(List models) { 32 | mapper.insertList(models); 33 | } 34 | 35 | public void deleteById(Integer id) { 36 | mapper.deleteByPrimaryKey(id); 37 | } 38 | 39 | public void deleteByIds(String ids) { 40 | mapper.deleteByIds(ids); 41 | } 42 | 43 | public void update(T model) { 44 | mapper.updateByPrimaryKeySelective(model); 45 | } 46 | 47 | public T findById(Integer id) { 48 | return mapper.selectByPrimaryKey(id); 49 | } 50 | 51 | @Override 52 | public T findBy(String fieldName, Object value) throws TooManyResultsException { 53 | try { 54 | T model = modelClass.newInstance(); 55 | Field field = modelClass.getDeclaredField(fieldName); 56 | field.setAccessible(true); 57 | field.set(model, value); 58 | return mapper.selectOne(model); 59 | } catch (ReflectiveOperationException e) { 60 | throw new ServiceException(e.getMessage(), e); 61 | } 62 | } 63 | 64 | public List findByIds(String ids) { 65 | return mapper.selectByIds(ids); 66 | } 67 | 68 | public List findByCondition(Condition condition) { 69 | return mapper.selectByCondition(condition); 70 | } 71 | 72 | public List findAll() { 73 | return mapper.selectAll(); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/com/company/project/core/Mapper.java: -------------------------------------------------------------------------------- 1 | package com.company.project.core; 2 | 3 | import tk.mybatis.mapper.common.BaseMapper; 4 | import tk.mybatis.mapper.common.ConditionMapper; 5 | import tk.mybatis.mapper.common.IdsMapper; 6 | import tk.mybatis.mapper.common.special.InsertListMapper; 7 | 8 | /** 9 | * 定制版MyBatis Mapper插件接口,如需其他接口参考官方文档自行添加。 10 | */ 11 | public interface Mapper 12 | extends 13 | BaseMapper, 14 | ConditionMapper, 15 | IdsMapper, 16 | InsertListMapper { 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/company/project/core/ProjectConstant.java: -------------------------------------------------------------------------------- 1 | package com.company.project.core; 2 | 3 | /** 4 | * 项目常量 5 | */ 6 | public final class ProjectConstant { 7 | public static final String BASE_PACKAGE = "com.company.project";//生成代码所在的基础包名称,可根据自己公司的项目修改(注意:这个配置修改之后需要手工修改src目录项目默认的包路径,使其保持一致,不然会找不到类) 8 | 9 | public static final String MODEL_PACKAGE = BASE_PACKAGE + ".model";//生成的Model所在包 10 | public static final String MAPPER_PACKAGE = BASE_PACKAGE + ".dao";//生成的Mapper所在包 11 | public static final String SERVICE_PACKAGE = BASE_PACKAGE + ".service";//生成的Service所在包 12 | public static final String SERVICE_IMPL_PACKAGE = SERVICE_PACKAGE + ".impl";//生成的ServiceImpl所在包 13 | public static final String CONTROLLER_PACKAGE = BASE_PACKAGE + ".web";//生成的Controller所在包 14 | 15 | public static final String MAPPER_INTERFACE_REFERENCE = BASE_PACKAGE + ".core.Mapper";//Mapper插件基础接口的完全限定名 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/company/project/core/Result.java: -------------------------------------------------------------------------------- 1 | package com.company.project.core; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | 5 | /** 6 | * 统一API响应结果封装 7 | */ 8 | public class Result { 9 | private int code; 10 | private String message; 11 | private T data; 12 | 13 | public Result setCode(ResultCode resultCode) { 14 | this.code = resultCode.code(); 15 | return this; 16 | } 17 | 18 | public int getCode() { 19 | return code; 20 | } 21 | 22 | public String getMessage() { 23 | return message; 24 | } 25 | 26 | public Result setMessage(String message) { 27 | this.message = message; 28 | return this; 29 | } 30 | 31 | public T getData() { 32 | return data; 33 | } 34 | 35 | public Result setData(T data) { 36 | this.data = data; 37 | return this; 38 | } 39 | 40 | @Override 41 | public String toString() { 42 | return JSON.toJSONString(this); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/company/project/core/ResultCode.java: -------------------------------------------------------------------------------- 1 | package com.company.project.core; 2 | 3 | /** 4 | * 响应码枚举,参考HTTP状态码的语义 5 | */ 6 | public enum ResultCode { 7 | SUCCESS(200),//成功 8 | FAIL(400),//失败 9 | UNAUTHORIZED(401),//未认证(签名错误) 10 | NOT_FOUND(404),//接口不存在 11 | INTERNAL_SERVER_ERROR(500);//服务器内部错误 12 | 13 | private final int code; 14 | 15 | ResultCode(int code) { 16 | this.code = code; 17 | } 18 | 19 | public int code() { 20 | return code; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/company/project/core/ResultGenerator.java: -------------------------------------------------------------------------------- 1 | package com.company.project.core; 2 | 3 | /** 4 | * 响应结果生成工具 5 | */ 6 | public class ResultGenerator { 7 | private static final String DEFAULT_SUCCESS_MESSAGE = "SUCCESS"; 8 | 9 | public static Result genSuccessResult() { 10 | return new Result() 11 | .setCode(ResultCode.SUCCESS) 12 | .setMessage(DEFAULT_SUCCESS_MESSAGE); 13 | } 14 | 15 | public static Result genSuccessResult(T data) { 16 | return new Result() 17 | .setCode(ResultCode.SUCCESS) 18 | .setMessage(DEFAULT_SUCCESS_MESSAGE) 19 | .setData(data); 20 | } 21 | 22 | public static Result genFailResult(String message) { 23 | return new Result() 24 | .setCode(ResultCode.FAIL) 25 | .setMessage(message); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/company/project/core/Service.java: -------------------------------------------------------------------------------- 1 | package com.company.project.core; 2 | 3 | import org.apache.ibatis.exceptions.TooManyResultsException; 4 | import tk.mybatis.mapper.entity.Condition; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * Service 层 基础接口,其他Service 接口 请继承该接口 10 | */ 11 | public interface Service { 12 | void save(T model);//持久化 13 | void save(List models);//批量持久化 14 | void deleteById(Integer id);//通过主鍵刪除 15 | void deleteByIds(String ids);//批量刪除 eg:ids -> “1,2,3,4” 16 | void update(T model);//更新 17 | T findById(Integer id);//通过ID查找 18 | T findBy(String fieldName, Object value) throws TooManyResultsException; //通过Model中某个成员变量名称(非数据表中column的名称)查找,value需符合unique约束 19 | List findByIds(String ids);//通过多个ID查找//eg:ids -> “1,2,3,4” 20 | List findByCondition(Condition condition);//根据条件查找 21 | List findAll();//获取所有 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/company/project/core/ServiceException.java: -------------------------------------------------------------------------------- 1 | package com.company.project.core; 2 | 3 | /** 4 | * 服务(业务)异常如“ 账号或密码错误 ”,该异常只做INFO级别的日志记录 @see WebMvcConfigurer 5 | */ 6 | public class ServiceException extends RuntimeException { 7 | public ServiceException() { 8 | } 9 | 10 | public ServiceException(String message) { 11 | super(message); 12 | } 13 | 14 | public ServiceException(String message, Throwable cause) { 15 | super(message, cause); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/resources/application-dev.properties: -------------------------------------------------------------------------------- 1 | # 开发环境配置 2 | # 数据源配置,请修改为你项目的实际配置 3 | spring.datasource.url=jdbc:mysql://localhost:3306/test 4 | spring.datasource.username=root 5 | spring.datasource.password=123456 6 | spring.datasource.driver-class-name=com.mysql.jdbc.Driver 7 | -------------------------------------------------------------------------------- /src/main/resources/application-prod.properties: -------------------------------------------------------------------------------- 1 | # 生产环境配置 2 | -------------------------------------------------------------------------------- /src/main/resources/application-test.properties: -------------------------------------------------------------------------------- 1 | # 测试环境配置 2 | -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.profiles.active=dev 2 | # 所有环境通用的配置,放在这里 3 | 4 | # 404 交给异常处理器处理 5 | spring.mvc.throw-exception-if-no-handler-found=true 6 | spring.resources.add-mappings=false 7 | -------------------------------------------------------------------------------- /src/main/resources/banner.txt: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////// 2 | // _ooOoo_ // 3 | // o8888888o // 4 | // 88" . "88 // 5 | // (| ^_^ |) // 6 | // O\ = /O // 7 | // ____/`---'\____ // 8 | // .' \\| |// `. // 9 | // / \\||| : |||// \ // 10 | // / _||||| -:- |||||- \ // 11 | // | | \\\ - /// | | // 12 | // | \_| ''\---/'' | | // 13 | // \ .-\__ `-` ___/-. / // 14 | // ___`. .' /--.--\ `. . ___ // 15 | // ."" '< `.___\_<|>_/___.' >'"". // 16 | // | | : `- \`.;`\ _ /`;.`/ - ` : | | // 17 | // \ \ `-. \_ __\ /__ _/ .-` / / // 18 | // ========`-.____`-.___\_____/___.-`____.-'======== // 19 | // `=---=' // 20 | // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ // 21 | // 佛祖保佑 永不宕机 永无BUG // 22 | //////////////////////////////////////////////////////////////////// -------------------------------------------------------------------------------- /src/test/java/CodeGenerator.java: -------------------------------------------------------------------------------- 1 | import com.google.common.base.CaseFormat; 2 | import freemarker.template.TemplateExceptionHandler; 3 | import org.apache.commons.lang3.StringUtils; 4 | import org.mybatis.generator.api.MyBatisGenerator; 5 | import org.mybatis.generator.config.*; 6 | import org.mybatis.generator.internal.DefaultShellCallback; 7 | 8 | import java.io.File; 9 | import java.io.FileWriter; 10 | import java.io.IOException; 11 | import java.text.SimpleDateFormat; 12 | import java.util.*; 13 | 14 | import static com.company.project.core.ProjectConstant.*; 15 | 16 | /** 17 | * 代码生成器,根据数据表名称生成对应的Model、Mapper、Service、Controller简化开发。 18 | */ 19 | public class CodeGenerator { 20 | //JDBC配置,请修改为你项目的实际配置 21 | private static final String JDBC_URL = "jdbc:mysql://localhost:3306/test"; 22 | private static final String JDBC_USERNAME = "root"; 23 | private static final String JDBC_PASSWORD = "123456"; 24 | private static final String JDBC_DIVER_CLASS_NAME = "com.mysql.jdbc.Driver"; 25 | 26 | private static final String PROJECT_PATH = System.getProperty("user.dir");//项目在硬盘上的基础路径 27 | private static final String TEMPLATE_FILE_PATH = PROJECT_PATH + "/src/test/resources/generator/template";//模板位置 28 | 29 | private static final String JAVA_PATH = "/src/main/java"; //java文件路径 30 | private static final String RESOURCES_PATH = "/src/main/resources";//资源文件路径 31 | 32 | private static final String PACKAGE_PATH_SERVICE = packageConvertPath(SERVICE_PACKAGE);//生成的Service存放路径 33 | private static final String PACKAGE_PATH_SERVICE_IMPL = packageConvertPath(SERVICE_IMPL_PACKAGE);//生成的Service实现存放路径 34 | private static final String PACKAGE_PATH_CONTROLLER = packageConvertPath(CONTROLLER_PACKAGE);//生成的Controller存放路径 35 | 36 | private static final String AUTHOR = "CodeGenerator";//@author 37 | private static final String DATE = new SimpleDateFormat("yyyy/MM/dd").format(new Date());//@date 38 | 39 | public static void main(String[] args) { 40 | genCode("输入表名"); 41 | //genCodeByCustomModelName("输入表名","输入自定义Model名称"); 42 | } 43 | 44 | /** 45 | * 通过数据表名称生成代码,Model 名称通过解析数据表名称获得,下划线转大驼峰的形式。 46 | * 如输入表名称 "t_user_detail" 将生成 TUserDetail、TUserDetailMapper、TUserDetailService ... 47 | * @param tableNames 数据表名称... 48 | */ 49 | public static void genCode(String... tableNames) { 50 | for (String tableName : tableNames) { 51 | genCodeByCustomModelName(tableName, null); 52 | } 53 | } 54 | 55 | /** 56 | * 通过数据表名称,和自定义的 Model 名称生成代码 57 | * 如输入表名称 "t_user_detail" 和自定义的 Model 名称 "User" 将生成 User、UserMapper、UserService ... 58 | * @param tableName 数据表名称 59 | * @param modelName 自定义的 Model 名称 60 | */ 61 | public static void genCodeByCustomModelName(String tableName, String modelName) { 62 | genModelAndMapper(tableName, modelName); 63 | genService(tableName, modelName); 64 | genController(tableName, modelName); 65 | } 66 | 67 | 68 | public static void genModelAndMapper(String tableName, String modelName) { 69 | Context context = new Context(ModelType.FLAT); 70 | context.setId("Potato"); 71 | context.setTargetRuntime("MyBatis3Simple"); 72 | context.addProperty(PropertyRegistry.CONTEXT_BEGINNING_DELIMITER, "`"); 73 | context.addProperty(PropertyRegistry.CONTEXT_ENDING_DELIMITER, "`"); 74 | 75 | JDBCConnectionConfiguration jdbcConnectionConfiguration = new JDBCConnectionConfiguration(); 76 | jdbcConnectionConfiguration.setConnectionURL(JDBC_URL); 77 | jdbcConnectionConfiguration.setUserId(JDBC_USERNAME); 78 | jdbcConnectionConfiguration.setPassword(JDBC_PASSWORD); 79 | jdbcConnectionConfiguration.setDriverClass(JDBC_DIVER_CLASS_NAME); 80 | context.setJdbcConnectionConfiguration(jdbcConnectionConfiguration); 81 | 82 | PluginConfiguration pluginConfiguration = new PluginConfiguration(); 83 | pluginConfiguration.setConfigurationType("tk.mybatis.mapper.generator.MapperPlugin"); 84 | pluginConfiguration.addProperty("mappers", MAPPER_INTERFACE_REFERENCE); 85 | context.addPluginConfiguration(pluginConfiguration); 86 | 87 | JavaModelGeneratorConfiguration javaModelGeneratorConfiguration = new JavaModelGeneratorConfiguration(); 88 | javaModelGeneratorConfiguration.setTargetProject(PROJECT_PATH + JAVA_PATH); 89 | javaModelGeneratorConfiguration.setTargetPackage(MODEL_PACKAGE); 90 | context.setJavaModelGeneratorConfiguration(javaModelGeneratorConfiguration); 91 | 92 | SqlMapGeneratorConfiguration sqlMapGeneratorConfiguration = new SqlMapGeneratorConfiguration(); 93 | sqlMapGeneratorConfiguration.setTargetProject(PROJECT_PATH + RESOURCES_PATH); 94 | sqlMapGeneratorConfiguration.setTargetPackage("mapper"); 95 | context.setSqlMapGeneratorConfiguration(sqlMapGeneratorConfiguration); 96 | 97 | JavaClientGeneratorConfiguration javaClientGeneratorConfiguration = new JavaClientGeneratorConfiguration(); 98 | javaClientGeneratorConfiguration.setTargetProject(PROJECT_PATH + JAVA_PATH); 99 | javaClientGeneratorConfiguration.setTargetPackage(MAPPER_PACKAGE); 100 | javaClientGeneratorConfiguration.setConfigurationType("XMLMAPPER"); 101 | context.setJavaClientGeneratorConfiguration(javaClientGeneratorConfiguration); 102 | 103 | TableConfiguration tableConfiguration = new TableConfiguration(context); 104 | tableConfiguration.setTableName(tableName); 105 | if (StringUtils.isNotEmpty(modelName))tableConfiguration.setDomainObjectName(modelName); 106 | tableConfiguration.setGeneratedKey(new GeneratedKey("id", "Mysql", true, null)); 107 | context.addTableConfiguration(tableConfiguration); 108 | 109 | List warnings; 110 | MyBatisGenerator generator; 111 | try { 112 | Configuration config = new Configuration(); 113 | config.addContext(context); 114 | config.validate(); 115 | 116 | boolean overwrite = true; 117 | DefaultShellCallback callback = new DefaultShellCallback(overwrite); 118 | warnings = new ArrayList(); 119 | generator = new MyBatisGenerator(config, callback, warnings); 120 | generator.generate(null); 121 | } catch (Exception e) { 122 | throw new RuntimeException("生成Model和Mapper失败", e); 123 | } 124 | 125 | if (generator.getGeneratedJavaFiles().isEmpty() || generator.getGeneratedXmlFiles().isEmpty()) { 126 | throw new RuntimeException("生成Model和Mapper失败:" + warnings); 127 | } 128 | if (StringUtils.isEmpty(modelName)) modelName = tableNameConvertUpperCamel(tableName); 129 | System.out.println(modelName + ".java 生成成功"); 130 | System.out.println(modelName + "Mapper.java 生成成功"); 131 | System.out.println(modelName + "Mapper.xml 生成成功"); 132 | } 133 | 134 | public static void genService(String tableName, String modelName) { 135 | try { 136 | freemarker.template.Configuration cfg = getConfiguration(); 137 | 138 | Map data = new HashMap<>(); 139 | data.put("date", DATE); 140 | data.put("author", AUTHOR); 141 | String modelNameUpperCamel = StringUtils.isEmpty(modelName) ? tableNameConvertUpperCamel(tableName) : modelName; 142 | data.put("modelNameUpperCamel", modelNameUpperCamel); 143 | data.put("modelNameLowerCamel", tableNameConvertLowerCamel(tableName)); 144 | data.put("basePackage", BASE_PACKAGE); 145 | 146 | File file = new File(PROJECT_PATH + JAVA_PATH + PACKAGE_PATH_SERVICE + modelNameUpperCamel + "Service.java"); 147 | if (!file.getParentFile().exists()) { 148 | file.getParentFile().mkdirs(); 149 | } 150 | cfg.getTemplate("service.ftl").process(data, 151 | new FileWriter(file)); 152 | System.out.println(modelNameUpperCamel + "Service.java 生成成功"); 153 | 154 | File file1 = new File(PROJECT_PATH + JAVA_PATH + PACKAGE_PATH_SERVICE_IMPL + modelNameUpperCamel + "ServiceImpl.java"); 155 | if (!file1.getParentFile().exists()) { 156 | file1.getParentFile().mkdirs(); 157 | } 158 | cfg.getTemplate("service-impl.ftl").process(data, 159 | new FileWriter(file1)); 160 | System.out.println(modelNameUpperCamel + "ServiceImpl.java 生成成功"); 161 | } catch (Exception e) { 162 | throw new RuntimeException("生成Service失败", e); 163 | } 164 | } 165 | 166 | public static void genController(String tableName, String modelName) { 167 | try { 168 | freemarker.template.Configuration cfg = getConfiguration(); 169 | 170 | Map data = new HashMap<>(); 171 | data.put("date", DATE); 172 | data.put("author", AUTHOR); 173 | String modelNameUpperCamel = StringUtils.isEmpty(modelName) ? tableNameConvertUpperCamel(tableName) : modelName; 174 | data.put("baseRequestMapping", modelNameConvertMappingPath(modelNameUpperCamel)); 175 | data.put("modelNameUpperCamel", modelNameUpperCamel); 176 | data.put("modelNameLowerCamel", CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_CAMEL, modelNameUpperCamel)); 177 | data.put("basePackage", BASE_PACKAGE); 178 | 179 | File file = new File(PROJECT_PATH + JAVA_PATH + PACKAGE_PATH_CONTROLLER + modelNameUpperCamel + "Controller.java"); 180 | if (!file.getParentFile().exists()) { 181 | file.getParentFile().mkdirs(); 182 | } 183 | //cfg.getTemplate("controller-restful.ftl").process(data, new FileWriter(file)); 184 | cfg.getTemplate("controller.ftl").process(data, new FileWriter(file)); 185 | 186 | System.out.println(modelNameUpperCamel + "Controller.java 生成成功"); 187 | } catch (Exception e) { 188 | throw new RuntimeException("生成Controller失败", e); 189 | } 190 | 191 | } 192 | 193 | private static freemarker.template.Configuration getConfiguration() throws IOException { 194 | freemarker.template.Configuration cfg = new freemarker.template.Configuration(freemarker.template.Configuration.VERSION_2_3_23); 195 | cfg.setDirectoryForTemplateLoading(new File(TEMPLATE_FILE_PATH)); 196 | cfg.setDefaultEncoding("UTF-8"); 197 | cfg.setTemplateExceptionHandler(TemplateExceptionHandler.IGNORE_HANDLER); 198 | return cfg; 199 | } 200 | 201 | private static String tableNameConvertLowerCamel(String tableName) { 202 | return CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, tableName.toLowerCase()); 203 | } 204 | 205 | private static String tableNameConvertUpperCamel(String tableName) { 206 | return CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, tableName.toLowerCase()); 207 | 208 | } 209 | 210 | private static String tableNameConvertMappingPath(String tableName) { 211 | tableName = tableName.toLowerCase();//兼容使用大写的表名 212 | return "/" + (tableName.contains("_") ? tableName.replaceAll("_", "/") : tableName); 213 | } 214 | 215 | private static String modelNameConvertMappingPath(String modelName) { 216 | String tableName = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, modelName); 217 | return tableNameConvertMappingPath(tableName); 218 | } 219 | 220 | private static String packageConvertPath(String packageName) { 221 | return String.format("/%s/", packageName.contains(".") ? packageName.replaceAll("\\.", "/") : packageName); 222 | } 223 | 224 | } 225 | -------------------------------------------------------------------------------- /src/test/java/com/conpany/project/Tester.java: -------------------------------------------------------------------------------- 1 | package com.conpany.project; 2 | 3 | 4 | import com.company.project.Application; 5 | import org.junit.runner.RunWith; 6 | import org.springframework.boot.test.context.SpringBootTest; 7 | import org.springframework.test.annotation.Rollback; 8 | import org.springframework.test.context.junit4.SpringRunner; 9 | import org.springframework.transaction.annotation.Transactional; 10 | 11 | /** 12 | * 单元测试继承该类即可 13 | */ 14 | @RunWith(SpringRunner.class) 15 | @SpringBootTest(classes = Application.class) 16 | @Transactional 17 | @Rollback 18 | public abstract class Tester {} 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/test/resources/demo-user.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Navicat MySQL Data Transfer 3 | 4 | Source Server : Localhost 5 | Source Server Version : 50713 6 | Source Host : localhost:3306 7 | Source Database : test 8 | 9 | Target Server Type : MYSQL 10 | Target Server Version : 50713 11 | File Encoding : 65001 12 | 13 | Date: 2017-06-23 14:25:27 14 | */ 15 | 16 | SET FOREIGN_KEY_CHECKS=0; 17 | 18 | -- ---------------------------- 19 | -- Table structure for user 20 | -- ---------------------------- 21 | DROP TABLE IF EXISTS `user`; 22 | CREATE TABLE `user` ( 23 | `id` int(11) NOT NULL AUTO_INCREMENT, 24 | `username` varchar(255) NOT NULL, 25 | `password` varchar(255) NOT NULL, 26 | `nick_name` varchar(255) DEFAULT NULL, 27 | `sex` int(1) DEFAULT NULL, 28 | `register_date` datetime NOT NULL, 29 | PRIMARY KEY (`id`) 30 | ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; 31 | 32 | -- ---------------------------- 33 | -- Records of user 34 | -- ---------------------------- 35 | INSERT INTO `user` VALUES ('1', '89921218@qq.com', '1ee04e0b1cb5af7367c80c22e42efd8b', '土豆', '1', '2017-06-23 14:24:23'); 36 | INSERT INTO `user` VALUES ('2', '2@qq.com', '1ee04e0b1cb5af7367c80c22e42efd8b', '土豆-2', '1', '2017-06-23 14:24:23'); 37 | INSERT INTO `user` VALUES ('3', '3@qq.com', '1ee04e0b1cb5af7367c80c22e42efd8b', '土豆-3', '1', '2017-06-23 14:24:23'); 38 | INSERT INTO `user` VALUES ('4', '4@qq.com', '1ee04e0b1cb5af7367c80c22e42efd8b', '土豆-4', '1', '2017-06-23 14:24:23'); 39 | INSERT INTO `user` VALUES ('5', '5@qq.com', '1ee04e0b1cb5af7367c80c22e42efd8b', '土豆-5', '1', '2017-06-23 14:24:23'); 40 | INSERT INTO `user` VALUES ('6', '6@qq.com', '1ee04e0b1cb5af7367c80c22e42efd8b', '土豆-6', '1', '2017-06-23 14:24:23'); 41 | INSERT INTO `user` VALUES ('7', '7@qq.com', '1ee04e0b1cb5af7367c80c22e42efd8b', '土豆-7', '1', '2017-06-23 14:24:23'); 42 | INSERT INTO `user` VALUES ('8', '8@qq.com', '1ee04e0b1cb5af7367c80c22e42efd8b', '土豆-8', '1', '2017-06-23 14:24:23'); 43 | INSERT INTO `user` VALUES ('9', '9@qq.com', '1ee04e0b1cb5af7367c80c22e42efd8b', '土豆-9', '1', '2017-06-23 14:24:23'); 44 | INSERT INTO `user` VALUES ('10', '10@qq.com', '1ee04e0b1cb5af7367c80c22e42efd8b', '土豆-10', '1', '2017-06-23 14:24:23'); 45 | SET FOREIGN_KEY_CHECKS=1; 46 | -------------------------------------------------------------------------------- /src/test/resources/generator/template/controller-restful.ftl: -------------------------------------------------------------------------------- 1 | package ${basePackage}.web; 2 | 3 | import ${basePackage}.core.Result; 4 | import ${basePackage}.core.ResultGenerator; 5 | import ${basePackage}.model.${modelNameUpperCamel}; 6 | import ${basePackage}.service.${modelNameUpperCamel}Service; 7 | import com.github.pagehelper.PageHelper; 8 | import com.github.pagehelper.PageInfo; 9 | import org.springframework.web.bind.annotation.*; 10 | 11 | import javax.annotation.Resource; 12 | import java.util.List; 13 | 14 | /** 15 | * Created by ${author} on ${date}. 16 | */ 17 | @RestController 18 | @RequestMapping("${baseRequestMapping}") 19 | public class ${modelNameUpperCamel}Controller { 20 | @Resource 21 | private ${modelNameUpperCamel}Service ${modelNameLowerCamel}Service; 22 | 23 | @PostMapping 24 | public Result add(@RequestBody ${modelNameUpperCamel} ${modelNameLowerCamel}) { 25 | ${modelNameLowerCamel}Service.save(${modelNameLowerCamel}); 26 | return ResultGenerator.genSuccessResult(); 27 | } 28 | 29 | @DeleteMapping("/{id}") 30 | public Result delete(@PathVariable Integer id) { 31 | ${modelNameLowerCamel}Service.deleteById(id); 32 | return ResultGenerator.genSuccessResult(); 33 | } 34 | 35 | @PutMapping 36 | public Result update(@RequestBody ${modelNameUpperCamel} ${modelNameLowerCamel}) { 37 | ${modelNameLowerCamel}Service.update(${modelNameLowerCamel}); 38 | return ResultGenerator.genSuccessResult(); 39 | } 40 | 41 | @GetMapping("/{id}") 42 | public Result detail(@PathVariable Integer id) { 43 | ${modelNameUpperCamel} ${modelNameLowerCamel} = ${modelNameLowerCamel}Service.findById(id); 44 | return ResultGenerator.genSuccessResult(${modelNameLowerCamel}); 45 | } 46 | 47 | @GetMapping 48 | public Result list(@RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "0") Integer size) { 49 | PageHelper.startPage(page, size); 50 | List<${modelNameUpperCamel}> list = ${modelNameLowerCamel}Service.findAll(); 51 | PageInfo pageInfo = new PageInfo(list); 52 | return ResultGenerator.genSuccessResult(pageInfo); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/test/resources/generator/template/controller.ftl: -------------------------------------------------------------------------------- 1 | package ${basePackage}.web; 2 | import ${basePackage}.core.Result; 3 | import ${basePackage}.core.ResultGenerator; 4 | import ${basePackage}.model.${modelNameUpperCamel}; 5 | import ${basePackage}.service.${modelNameUpperCamel}Service; 6 | import com.github.pagehelper.PageHelper; 7 | import com.github.pagehelper.PageInfo; 8 | import org.springframework.web.bind.annotation.PostMapping; 9 | import org.springframework.web.bind.annotation.RequestMapping; 10 | import org.springframework.web.bind.annotation.RequestParam; 11 | import org.springframework.web.bind.annotation.RestController; 12 | 13 | import javax.annotation.Resource; 14 | import java.util.List; 15 | 16 | /** 17 | * Created by ${author} on ${date}. 18 | */ 19 | @RestController 20 | @RequestMapping("${baseRequestMapping}") 21 | public class ${modelNameUpperCamel}Controller { 22 | @Resource 23 | private ${modelNameUpperCamel}Service ${modelNameLowerCamel}Service; 24 | 25 | @PostMapping("/add") 26 | public Result add(${modelNameUpperCamel} ${modelNameLowerCamel}) { 27 | ${modelNameLowerCamel}Service.save(${modelNameLowerCamel}); 28 | return ResultGenerator.genSuccessResult(); 29 | } 30 | 31 | @PostMapping("/delete") 32 | public Result delete(@RequestParam Integer id) { 33 | ${modelNameLowerCamel}Service.deleteById(id); 34 | return ResultGenerator.genSuccessResult(); 35 | } 36 | 37 | @PostMapping("/update") 38 | public Result update(${modelNameUpperCamel} ${modelNameLowerCamel}) { 39 | ${modelNameLowerCamel}Service.update(${modelNameLowerCamel}); 40 | return ResultGenerator.genSuccessResult(); 41 | } 42 | 43 | @PostMapping("/detail") 44 | public Result detail(@RequestParam Integer id) { 45 | ${modelNameUpperCamel} ${modelNameLowerCamel} = ${modelNameLowerCamel}Service.findById(id); 46 | return ResultGenerator.genSuccessResult(${modelNameLowerCamel}); 47 | } 48 | 49 | @PostMapping("/list") 50 | public Result list(@RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "0") Integer size) { 51 | PageHelper.startPage(page, size); 52 | List<${modelNameUpperCamel}> list = ${modelNameLowerCamel}Service.findAll(); 53 | PageInfo pageInfo = new PageInfo(list); 54 | return ResultGenerator.genSuccessResult(pageInfo); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/test/resources/generator/template/service-impl.ftl: -------------------------------------------------------------------------------- 1 | package ${basePackage}.service.impl; 2 | 3 | import ${basePackage}.dao.${modelNameUpperCamel}Mapper; 4 | import ${basePackage}.model.${modelNameUpperCamel}; 5 | import ${basePackage}.service.${modelNameUpperCamel}Service; 6 | import ${basePackage}.core.AbstractService; 7 | import org.springframework.stereotype.Service; 8 | import org.springframework.transaction.annotation.Transactional; 9 | 10 | import javax.annotation.Resource; 11 | 12 | 13 | /** 14 | * Created by ${author} on ${date}. 15 | */ 16 | @Service 17 | @Transactional 18 | public class ${modelNameUpperCamel}ServiceImpl extends AbstractService<${modelNameUpperCamel}> implements ${modelNameUpperCamel}Service { 19 | @Resource 20 | private ${modelNameUpperCamel}Mapper ${modelNameLowerCamel}Mapper; 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/test/resources/generator/template/service.ftl: -------------------------------------------------------------------------------- 1 | package ${basePackage}.service; 2 | import ${basePackage}.model.${modelNameUpperCamel}; 3 | import ${basePackage}.core.Service; 4 | 5 | 6 | /** 7 | * Created by ${author} on ${date}. 8 | */ 9 | public interface ${modelNameUpperCamel}Service extends Service<${modelNameUpperCamel}> { 10 | 11 | } 12 | --------------------------------------------------------------------------------