diff --git a/README.md b/README.md index 5ad7d97a5..14d576c76 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,19 @@ ![Licence](https://img.shields.io/badge/licence-none-green.svg) [![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) + ## 简介 +基于原来的工程改动太大,所以自己fork过来进行了修改。主要修改点如下: + +1、SprintBoot升级到目前最新版本,2.1.3; + +2、HttpMessageConverter改为默认的Jackson; + +3、打包自动化并且添加一些启动和停止脚本,打包成一个tar.gz包; + +4、添加了一个DEMO,原则上应该删除掉,懒,就懒得删了。 + +
+ Spring Boot API Project Seed 是一个基于Spring Boot & MyBatis的种子项目,用于快速构建中小型API、RESTful API项目,该种子项目已经有过多个真实项目的实践,稳定、简单、快速,使我们摆脱那些重复劳动,专注于业务代码的编写,减少加班。下面是一个简单的使用演示,看如何基于本项目在短短几十秒钟内实现一套简单的API,并运行提供服务。 [![请选择超清](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) @@ -15,7 +28,7 @@ Spring Boot API Project Seed 是一个基于Spring Boot & MyBatis的种子项目 - 集成MyBatis、通用Mapper插件、PageHelper分页插件,实现单表业务零SQL - 提供代码生成器根据表名生成对应的Model、Mapper、MapperXML、Service、ServiceImpl、Controller等基础代码,其中Controller模板默认提供POST和RESTful两套,根据需求在```CodeGenerator.genController(tableName)```方法中自己选择,默认使用POST模板。代码模板可根据实际项目的需求来扩展,由于每个公司业务都不太一样,所以只提供了一些比较基础、通用的模板,**主要是提供一个思路**来减少重复代码的编写,我在实际项目的使用中,其实根据公司业务的抽象编写了大量的模板。另外,使用模板也有助于保持团队代码风格的统一 - 另有彩蛋,待你探索 -  + ## 快速开始 1. 克隆项目 2. 对```test```包内的代码生成器```CodeGenerator```进行配置,主要是JDBC,因为要根据表名来生成代码 @@ -23,7 +36,7 @@ Spring Boot API Project Seed 是一个基于Spring Boot & MyBatis的种子项目 3. 输入表名,运行```CodeGenerator.main()```方法,生成基础代码(可能需要刷新项目目录才会出来) 4. 根据业务在基础代码上进行扩展 5. 对开发环境配置文件```application-dev.properties```进行配置,启动项目,Have Fun! -  + ## 开发建议 - 表名,建议使用小写,多个单词使用下划线拼接 - Model内成员变量建议与表字段数量对应,如需扩展成员变量(比如连表查询)建议创建DTO,否则需在扩展的成员变量上加```@Transient```注解,详情见[通用Mapper插件文档说明](https://mapperhelper.github.io/docs/2.use/) @@ -31,7 +44,7 @@ Spring Boot API Project Seed 是一个基于Spring Boot & MyBatis的种子项目 - 需要工具类的话建议先从```apache-commons-*```和```guava```中找,实在没有再造轮子或引入类库,尽量精简项目 - 开发规范建议遵循阿里巴巴Java开发手册([最新版下载](https://github.com/alibaba/p3c)) - 建议在公司内部使用[ShowDoc](https://github.com/star7th/showdoc)、[SpringFox-Swagger2](https://github.com/springfox/springfox) 、[RAP](https://github.com/thx/RAP)等开源项目来编写、管理API文档 -  + ## 技术选型&文档 - Spring Boot([查看Spring Boot学习&使用指南](http://www.jianshu.com/p/1a9fd8936bd8)) - MyBatis([查看官方中文文档](http://www.mybatis.org/mybatis-3/zh/index.html)) diff --git a/pom.xml b/pom.xml index 80cf9affc..2f7b321b4 100644 --- a/pom.xml +++ b/pom.xml @@ -11,13 +11,20 @@ 1.8 + UTF-8 + 1.8 + 1.8 + + + 2.9.8 + org.springframework.boot spring-boot-starter-parent - 1.5.13.RELEASE + 2.1.3.RELEASE @@ -25,6 +32,12 @@ org.springframework.boot spring-boot-starter-web + + + com.fasterxml.jackson.core + jackson-annotations + + org.springframework.boot @@ -70,7 +83,7 @@ tk.mybatis mapper - 3.4.2 + 4.1.5 com.github.pagehelper @@ -78,11 +91,30 @@ 4.2.1 - + + + + com.fasterxml.jackson.core + jackson-annotations + ${jackson.version} + + + + com.fasterxml.jackson.dataformat + jackson-dataformat-xml + ${jackson.version} + + + com.fasterxml.jackson.core + jackson-annotations + + + com.alibaba @@ -106,10 +138,6 @@ - - org.springframework.boot - spring-boot-maven-plugin - maven-compiler-plugin @@ -118,6 +146,83 @@ UTF-8 + + + + org.apache.maven.plugins + maven-jar-plugin + + ${project.artifactId}-${project.version} + + *.xml + *.properties + */*.xml + + + + true + com.company.project.AppStarter + + lib/ + + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + unpack + package + + unpack + + + + + ${project.groupId} + ${project.artifactId} + ${project.version} + + + + + + + + + maven-assembly-plugin + + seed-test + + src/main/assembly/assembly.xml + + + + + make-assembly + package + + single + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + true + + + diff --git a/src/main/assembly/assembly.xml b/src/main/assembly/assembly.xml new file mode 100644 index 000000000..fc7610fd7 --- /dev/null +++ b/src/main/assembly/assembly.xml @@ -0,0 +1,55 @@ + + + assembly + + tar.gz + + + true + + + src/main/assembly/bin + bin + 0755 + + + src/main/resources/ + + config + 0644 + + + + + ${project.build.directory} + . + + *.jar + + + + + + + + false + lib + + + \ No newline at end of file diff --git a/src/main/assembly/bin/dump.sh b/src/main/assembly/bin/dump.sh new file mode 100644 index 000000000..29006a60f --- /dev/null +++ b/src/main/assembly/bin/dump.sh @@ -0,0 +1,92 @@ +#!/bin/bash +cd `dirname $0` +BIN_DIR=`pwd` +cd .. +DEPLOY_DIR=`pwd` +CONF_DIR=${DEPLOY_DIR}/config + +SERVER_NAME=`sed '/server.servlet.application-display-name/!d;s/.*=//' config/application.properties | tr -d '\r'` +LOGS_FILE=`sed '/logging.path/!d;s/.*=//' config/application.properties | tr -d '\r'` + +if [ -z "$SERVER_NAME" ]; then + SERVER_NAME=`hostname` +fi + +PIDS=`ps -ef | grep java | grep "$CONF_DIR" |awk '{print $2}'` +if [ -z "$PIDS" ]; then + echo "ERROR: The $SERVER_NAME does not started!" + exit 1 +fi + +LOGS_DIR="" +if [ -n "$LOGS_FILE" ]; then + LOGS_DIR=`dirname ${LOGS_FILE}` +else + LOGS_DIR=$HOME/logs +fi +if [ ! -d ${LOGS_DIR} ]; then + mkdir ${LOGS_DIR} +fi +DUMP_DIR=${LOGS_DIR}/dump-${SERVER_NAME} +if [ ! -d ${DUMP_DIR} ]; then + mkdir ${DUMP_DIR} +fi +DUMP_DATE=`date +%Y%m%d%H%M%S` +DATE_DIR=${DUMP_DIR}/${DUMP_DATE} +if [ ! -d ${DATE_DIR} ]; then + mkdir ${DATE_DIR} +fi + +echo -e "Dumping the $SERVER_NAME ...\c" +for PID in ${PIDS} ; do + jstack ${PID} > ${DATE_DIR}/jstack-${PID}.dump 2>&1 + echo -e ".\c" + jinfo ${PID} > ${DATE_DIR}/jinfo-${PID}.dump 2>&1 + echo -e ".\c" + jstat -gcutil ${PID} > ${DATE_DIR}/jstat-gcutil-${PID}.dump 2>&1 + echo -e ".\c" + jstat -gccapacity ${PID} > ${DATE_DIR}/jstat-gccapacity-${PID}.dump 2>&1 + echo -e ".\c" + jmap ${PID} > ${DATE_DIR}/jmap-${PID}.dump 2>&1 + echo -e ".\c" + jmap -heap ${PID} > ${DATE_DIR}/jmap-heap-${PID}.dump 2>&1 + echo -e ".\c" + jmap -histo ${PID} > ${DATE_DIR}/jmap-histo-${PID}.dump 2>&1 + echo -e ".\c" + if [ -r /usr/sbin/lsof ]; then + /usr/sbin/lsof -p ${PID} > ${DATE_DIR}/lsof-${PID}.dump + echo -e ".\c" + fi +done + +if [ -r /bin/netstat ]; then +/bin/netstat -an > ${DATE_DIR}/netstat.dump 2>&1 +echo -e ".\c" +fi +if [ -r /usr/bin/iostat ]; then +/usr/bin/iostat > ${DATE_DIR}/iostat.dump 2>&1 +echo -e ".\c" +fi +if [ -r /usr/bin/mpstat ]; then +/usr/bin/mpstat > ${DATE_DIR}/mpstat.dump 2>&1 +echo -e ".\c" +fi +if [ -r /usr/bin/vmstat ]; then +/usr/bin/vmstat > ${DATE_DIR}/vmstat.dump 2>&1 +echo -e ".\c" +fi +if [ -r /usr/bin/free ]; then +/usr/bin/free -t > ${DATE_DIR}/free.dump 2>&1 +echo -e ".\c" +fi +if [ -r /usr/bin/sar ]; then +/usr/bin/sar > ${DATE_DIR}/sar.dump 2>&1 +echo -e ".\c" +fi +if [ -r /usr/bin/uptime ]; then +/usr/bin/uptime > ${DATE_DIR}/uptime.dump 2>&1 +echo -e ".\c" +fi + +echo "OK!" +echo "DUMP: $DATE_DIR" diff --git a/src/main/assembly/bin/restart.sh b/src/main/assembly/bin/restart.sh new file mode 100644 index 000000000..647ec1951 --- /dev/null +++ b/src/main/assembly/bin/restart.sh @@ -0,0 +1,4 @@ +#!/bin/bash +cd `dirname $0` +./stop.sh +./start.sh diff --git a/src/main/assembly/bin/server.sh b/src/main/assembly/bin/server.sh new file mode 100644 index 000000000..90947a5de --- /dev/null +++ b/src/main/assembly/bin/server.sh @@ -0,0 +1,24 @@ +#!/bin/bash +cd `dirname $0` +if [ "$1" = "start" ]; then + ./start.sh +else + if [ "$1" = "stop" ]; then + ./stop.sh + else + if [ "$1" = "debug" ]; then + ./start.sh debug + else + if [ "$1" = "restart" ]; then + ./restart.sh + else + if [ "$1" = "dump" ]; then + ./dump.sh + else + echo "ERROR: Please input argument: start or stop or debug or restart or dump" + exit 1 + fi + fi + fi + fi +fi diff --git a/src/main/assembly/bin/start.sh b/src/main/assembly/bin/start.sh new file mode 100644 index 000000000..5d4602987 --- /dev/null +++ b/src/main/assembly/bin/start.sh @@ -0,0 +1,97 @@ +#!/bin/bash +cd `dirname $0` +BIN_DIR=`pwd` +cd .. +DEPLOY_DIR=`pwd` +CONF_DIR=${DEPLOY_DIR}/config + +SERVER_NAME=`sed '/server.servlet.application-display-name/!d;s/.*=//' config/application.properties | tr -d '\r'` +SERVER_PORT=`sed '/server.port/!d;s/.*=//' config/application.properties | tr -d '\r'` +PROFILES_ACTIVE=`sed '/spring.profiles.active/!d;s/.*=//' config/application.properties | tr -d '\r'` +LOGS_FILE=`sed '/logging.path/!d;s/.*=//' config/application.properties | tr -d '\r'` + +ACTIVE_FILE=application-"$PROFILES_ACTIVE".properties +EXECUTE_FILE=spring-boot-api-project-seed-1.0.jar + +if [ -z "$SERVER_NAME" ]; then + SERVER_NAME=`hostname` +fi + +PIDS=`ps -ef | grep java | grep "$CONF_DIR" |awk '{print $2}'` +if [ -n "$PIDS" ]; then + echo "ERROR: The $SERVER_NAME already started!" + echo "PID: $PIDS" + exit 1 +fi + +if [ -n "$SERVER_PORT" ]; then + SERVER_PORT_COUNT=`netstat -tln | grep ${SERVER_PORT} | wc -l` + if [ ${SERVER_PORT_COUNT} -gt 0 ]; then + echo "ERROR: The $SERVER_NAME port $SERVER_PORT already used!" + exit 1 + fi +fi + +LOGS_DIR="" +if [ -n "$LOGS_FILE" ]; then + LOGS_DIR=`dirname ${LOGS_FILE}` +else + LOGS_DIR=$HOME/logs +fi +if [ ! -d ${LOGS_DIR} ]; then + mkdir ${LOGS_DIR} +fi +STDOUT_FILE=${LOGS_DIR}/stdout-${SERVER_NAME}.log + +LIB_DIR=${DEPLOY_DIR}/lib +LIB_JARS=`ls ${LIB_DIR}|grep .jar|awk '{print "'${LIB_DIR}'/"$0}'|tr "\n" ":"` + +JAVA_OPTS=" -Djava.awt.headless=true -Djava.net.preferIPv4Stack=true " +JAVA_DEBUG_OPTS="" +if [ "$1" = "debug" ]; then + JAVA_DEBUG_OPTS=" -Xdebug -Xnoagent -Djava.compiler=NONE \ + -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n " +fi +JAVA_JMX_OPTS="" +if [ "$1" = "jmx" ]; then + JAVA_JMX_OPTS=" -Dcom.sun.management.jmxremote.port=1099 -Dcom.sun.management.jmxremote.ssl=false \ + -Dcom.sun.management.jmxremote.authenticate=false " +fi +JAVA_MEM_OPTS="" +BITS=`java -version 2>&1 | grep -i 64-bit` +if [ -n "$BITS" ]; then + JAVA_MEM_OPTS=" -server -Xmx2g -Xms2g -Xmn256m -Xss256k -XX:+DisableExplicitGC -XX:+UseConcMarkSweepGC \ + -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:LargePageSizeInBytes=128m \ + -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70 " +else + JAVA_MEM_OPTS=" -server -Xms1g -Xmx1g -XX:SurvivorRatio=2 -XX:+UseParallelGC " +fi + +echo -e "Starting the $SERVER_NAME ...\c" + +nohup java ${JAVA_OPTS} ${JAVA_MEM_OPTS} ${JAVA_DEBUG_OPTS} ${JAVA_JMX_OPTS} \ +-Dloader.path=${LIB_DIR},${CONF_DIR} -jar ${DEPLOY_DIR}/${EXECUTE_FILE} > ${STDOUT_FILE} 2>&1 & +#-Dspring.config.location=${CONF_DIR}/application.properties,${CONF_DIR}/${ACTIVE_FILE} > ${STDOUT_FILE} 2>&1 & + +# 最长检测 1 分钟,可能的结果是标志文件不存在,这个要开发人员自己检查进程启动是否有问题. +CHECK_MAX_COUNT=30 +COUNT=0 +while [ ${CHECK_MAX_COUNT} -gt 1 ]; do + echo -e ".\c" + sleep 2 + if [ -n "$SERVER_PORT" ]; then + COUNT=`netstat -an | grep ${SERVER_PORT} | wc -l` + else + COUNT=`ps -ef | grep java | grep "$DEPLOY_DIR" | awk '{print $2}' | wc -l` + fi + if [ ${COUNT} -gt 0 ]; then + break + fi + + ((CHECK_MAX_COUNT--)) +done + +echo "OK!" +PIDS=`ps -ef | grep java | grep "$DEPLOY_DIR" | awk '{print $2}'` +echo "PID: $PIDS" +echo "STDOUT: $STDOUT_FILE" diff --git a/src/main/assembly/bin/stop.sh b/src/main/assembly/bin/stop.sh new file mode 100644 index 000000000..c0ee67a74 --- /dev/null +++ b/src/main/assembly/bin/stop.sh @@ -0,0 +1,44 @@ +#!/bin/bash +cd `dirname $0` +BIN_DIR=`pwd` +cd .. +DEPLOY_DIR=`pwd` +CONF_DIR=${DEPLOY_DIR}/config + +SERVER_NAME=`sed '/server.servlet.application-display-name/!d;s/.*=//' config/application.properties | tr -d '\r'` + +if [ -z "$SERVER_NAME" ]; then + SERVER_NAME=`hostname` +fi + +PIDS=`ps -ef | grep java | grep "$CONF_DIR" |awk '{print $2}'` +if [ -z "$PIDS" ]; then + echo "ERROR: The $SERVER_NAME does not started!" + exit 1 +fi + +if [ "$1" != "skip" ]; then + ${BIN_DIR}/dump.sh +fi + +echo -e "Stopping the $SERVER_NAME ...\c" +for PID in ${PIDS} ; do + kill ${PID} > /dev/null 2>&1 +done + +COUNT=0 +while [ ${COUNT} -lt 1 ]; do + echo -e ".\c" + sleep 1 + COUNT=1 + for PID in ${PIDS} ; do + PID_EXIST=`ps -p ${PID} | grep java` + if [ -n "$PID_EXIST" ]; then + COUNT=0 + break + fi + done +done + +echo "OK!" +echo "PID: $PIDS" diff --git a/src/main/java/com/company/project/Application.java b/src/main/java/com/company/project/AppStarter.java similarity index 50% rename from src/main/java/com/company/project/Application.java rename to src/main/java/com/company/project/AppStarter.java index da17b6a1a..07e86c484 100644 --- a/src/main/java/com/company/project/Application.java +++ b/src/main/java/com/company/project/AppStarter.java @@ -2,11 +2,18 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.web.bind.annotation.RequestMapping; @SpringBootApplication -public class Application { +public class AppStarter { + + @RequestMapping("/") + String home() { + return "Hello World!"; + } + public static void main(String[] args) { - SpringApplication.run(Application.class, args); + SpringApplication.run(AppStarter.class, args); } } diff --git a/src/main/java/com/company/project/configurer/WebMvcConfigurer.java b/src/main/java/com/company/project/configurer/MyWebMvcConfigurer.java similarity index 55% rename from src/main/java/com/company/project/configurer/WebMvcConfigurer.java rename to src/main/java/com/company/project/configurer/MyWebMvcConfigurer.java index c9460d3fc..6b9859352 100644 --- a/src/main/java/com/company/project/configurer/WebMvcConfigurer.java +++ b/src/main/java/com/company/project/configurer/MyWebMvcConfigurer.java @@ -1,21 +1,6 @@ package com.company.project.configurer; -import java.io.IOException; -import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.serializer.SerializerFeature; -import com.alibaba.fastjson.support.config.FastJsonConfig; -import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter; - +import com.company.project.core.CustomObjectMapper; import com.company.project.core.Result; import com.company.project.core.ResultCode; import com.company.project.core.ServiceException; @@ -25,100 +10,120 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; -import org.springframework.http.MediaType; import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.HandlerExceptionResolver; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.NoHandlerFoundException; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; +import javax.annotation.Resource; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + /** * Spring MVC 配置 */ @Configuration -public class WebMvcConfigurer extends WebMvcConfigurerAdapter { +public class MyWebMvcConfigurer implements WebMvcConfigurer { - private final Logger logger = LoggerFactory.getLogger(WebMvcConfigurer.class); + private final Logger logger = LoggerFactory.getLogger(MyWebMvcConfigurer.class); + /** + * 当前激活的配置文件 + */ @Value("${spring.profiles.active}") - private String env;//当前激活的配置文件 + private String env; - //使用阿里 FastJson 作为JSON MessageConverter + @Resource + private CustomObjectMapper objectMapper; + + /** + * 使用Jackson作为JSON MessageConverter + * + * @param converters + */ @Override public void configureMessageConverters(List> converters) { - FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter(); - FastJsonConfig config = new FastJsonConfig(); - config.setSerializerFeatures(SerializerFeature.WriteMapNullValue);//保留空的字段 - //SerializerFeature.WriteNullStringAsEmpty,//String null -> "" - //SerializerFeature.WriteNullNumberAsZero//Number null -> 0 - // 按需配置,更多参考FastJson文档哈 - - converter.setFastJsonConfig(config); - converter.setDefaultCharset(Charset.forName("UTF-8")); - converter.setSupportedMediaTypes(Arrays.asList(MediaType.APPLICATION_JSON_UTF8)); + MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); + converter.setObjectMapper(objectMapper); converters.add(converter); } - //统一异常处理 + /** + * 统一异常处理 + * + * @param exceptionResolvers + */ @Override public void configureHandlerExceptionResolvers(List exceptionResolvers) { - exceptionResolvers.add(new HandlerExceptionResolver() { - public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception e) { - Result result = new Result(); - if (e instanceof ServiceException) {//业务失败的异常,如“账号或密码错误” - result.setCode(ResultCode.FAIL).setMessage(e.getMessage()); - logger.info(e.getMessage()); - } else if (e instanceof NoHandlerFoundException) { - result.setCode(ResultCode.NOT_FOUND).setMessage("接口 [" + request.getRequestURI() + "] 不存在"); - } else if (e instanceof ServletException) { - result.setCode(ResultCode.FAIL).setMessage(e.getMessage()); + exceptionResolvers.add((request, response, handler, e) -> { + Result result = new Result(); + // 业务失败的异常,如“账号或密码错误” + if (e instanceof ServiceException) { + result.setCode(ResultCode.FAIL).setMessage(e.getMessage()); + logger.info(e.getMessage()); + } else if (e instanceof NoHandlerFoundException) { + result.setCode(ResultCode.NOT_FOUND).setMessage("接口 [" + request.getRequestURI() + "] 不存在"); + } else if (e instanceof ServletException) { + result.setCode(ResultCode.FAIL).setMessage(e.getMessage()); + } else { + result.setCode(ResultCode.INTERNAL_SERVER_ERROR).setMessage("接口 [" + request.getRequestURI() + "] 内部错误,请联系管理员"); + String message; + if (handler instanceof HandlerMethod) { + HandlerMethod handlerMethod = (HandlerMethod) handler; + message = String.format("接口 [%s] 出现异常,方法:%s.%s,异常摘要:%s", + request.getRequestURI(), + handlerMethod.getBean().getClass().getName(), + handlerMethod.getMethod().getName(), + e.getMessage()); } else { - result.setCode(ResultCode.INTERNAL_SERVER_ERROR).setMessage("接口 [" + request.getRequestURI() + "] 内部错误,请联系管理员"); - String message; - if (handler instanceof HandlerMethod) { - HandlerMethod handlerMethod = (HandlerMethod) handler; - message = String.format("接口 [%s] 出现异常,方法:%s.%s,异常摘要:%s", - request.getRequestURI(), - handlerMethod.getBean().getClass().getName(), - handlerMethod.getMethod().getName(), - e.getMessage()); - } else { - message = e.getMessage(); - } - logger.error(message, e); + message = e.getMessage(); } - responseResult(response, result); - return new ModelAndView(); + logger.error(message, e); } - + responseResult(response, result); + return new ModelAndView(); }); } - //解决跨域问题 + /** + * 解决跨域问题 + * + * @param registry + */ @Override public void addCorsMappings(CorsRegistry registry) { //registry.addMapping("/**"); } - //添加拦截器 + /** + * 添加拦截器 + */ @Override public void addInterceptors(InterceptorRegistry registry) { //接口签名认证拦截器,该签名认证比较简单,实际项目中可以使用Json Web Token或其他更好的方式替代。 - if (!"dev".equals(env)) { //开发环境忽略签名认证 + //开发环境忽略签名认证 + if (!"dev".equals(env)) { registry.addInterceptor(new HandlerInterceptorAdapter() { @Override - public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { //验证签名 boolean pass = validateSign(request); if (pass) { return true; } else { logger.warn("签名认证失败,请求接口:{},请求IP:{},请求参数:{}", - request.getRequestURI(), getIpAddress(request), JSON.toJSONString(request.getParameterMap())); + request.getRequestURI(), getIpAddress(request), objectMapper.toJSONString(request.getParameterMap())); Result result = new Result(); result.setCode(ResultCode.UNAUTHORIZED).setMessage("签名认证失败"); @@ -135,7 +140,7 @@ private void responseResult(HttpServletResponse response, Result result) { response.setHeader("Content-type", "application/json;charset=UTF-8"); response.setStatus(200); try { - response.getWriter().write(JSON.toJSONString(result)); + response.getWriter().write(objectMapper.toJSONString(result)); } catch (IOException ex) { logger.error(ex.getMessage()); } @@ -148,25 +153,33 @@ private void responseResult(HttpServletResponse response, Result result) { * 3. 混合密钥(secret)进行md5获得签名,与请求的签名进行比较 */ private boolean validateSign(HttpServletRequest request) { - String requestSign = request.getParameter("sign");//获得请求签名,如sign=19e907700db7ad91318424a97c54ed57 + // 获得请求签名,如sign=19e907700db7ad91318424a97c54ed57 + String requestSign = request.getParameter("sign"); if (StringUtils.isEmpty(requestSign)) { return false; } - List keys = new ArrayList(request.getParameterMap().keySet()); - keys.remove("sign");//排除sign参数 - Collections.sort(keys);//排序 + List keys = new ArrayList<>(request.getParameterMap().keySet()); + // 排除sign参数 + keys.remove("sign"); + // 排序 + Collections.sort(keys); StringBuilder sb = new StringBuilder(); for (String key : keys) { - sb.append(key).append("=").append(request.getParameter(key)).append("&");//拼接字符串 + // 拼接字符串 + sb.append(key).append("=").append(request.getParameter(key)).append("&"); } String linkString = sb.toString(); - linkString = StringUtils.substring(linkString, 0, linkString.length() - 1);//去除最后一个'&' + // 去除最后一个'&' + linkString = StringUtils.substring(linkString, 0, linkString.length() - 1); - String secret = "Potato";//密钥,自己修改 - String sign = DigestUtils.md5Hex(linkString + secret);//混合密钥md5 + // 密钥,自己修改 + String secret = "Potato"; + // 混合密钥md5 + String sign = DigestUtils.md5Hex(linkString + secret); - return StringUtils.equals(sign, requestSign);//比较 + // 比较 + return StringUtils.equals(sign, requestSign); } private String getIpAddress(HttpServletRequest request) { @@ -187,7 +200,7 @@ private String getIpAddress(HttpServletRequest request) { ip = request.getRemoteAddr(); } // 如果是多级代理,那么取第一个ip为客户端ip - if (ip != null && ip.indexOf(",") != -1) { + if (ip != null && ip.contains(",")) { ip = ip.substring(0, ip.indexOf(",")).trim(); } diff --git a/src/main/java/com/company/project/configurer/MybatisConfigurer.java b/src/main/java/com/company/project/configurer/MybatisConfigurer.java index 0d6487d86..cc31e804e 100644 --- a/src/main/java/com/company/project/configurer/MybatisConfigurer.java +++ b/src/main/java/com/company/project/configurer/MybatisConfigurer.java @@ -4,20 +4,16 @@ import org.apache.ibatis.plugin.Interceptor; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionFactoryBean; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternResolver; import tk.mybatis.spring.mapper.MapperScannerConfigurer; -import javax.annotation.Resource; import javax.sql.DataSource; import java.util.Properties; -import static com.company.project.core.ProjectConstant.*; +import static com.company.project.core.ProjectConstants.*; /** * Mybatis & Mapper & PageHelper 配置 @@ -31,12 +27,15 @@ public SqlSessionFactory sqlSessionFactoryBean(DataSource dataSource) throws Exc factory.setDataSource(dataSource); factory.setTypeAliasesPackage(MODEL_PACKAGE); - //配置分页插件,详情请查阅官方文档 + // 配置分页插件,详情请查阅官方文档 PageHelper pageHelper = new PageHelper(); Properties properties = new Properties(); - properties.setProperty("pageSizeZero", "true");//分页尺寸为0时查询所有纪录不再执行分页 - properties.setProperty("reasonable", "true");//页码<=0 查询第一页,页码>=总页数查询最后一页 - properties.setProperty("supportMethodsArguments", "true");//支持通过 Mapper 接口参数来传递分页参数 + // 分页尺寸为0时查询所有纪录不再执行分页 + properties.setProperty("pageSizeZero", "true"); + // 页码<=0 查询第一页,页码>=总页数查询最后一页 + properties.setProperty("reasonable", "true"); + // 支持通过 Mapper 接口参数来传递分页参数 + properties.setProperty("supportMethodsArguments", "true"); pageHelper.setProperties(properties); //添加插件 @@ -54,10 +53,11 @@ public MapperScannerConfigurer mapperScannerConfigurer() { mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactoryBean"); mapperScannerConfigurer.setBasePackage(MAPPER_PACKAGE); - //配置通用Mapper,详情请查阅官方文档 + // 配置通用Mapper,详情请查阅官方文档 Properties properties = new Properties(); properties.setProperty("mappers", MAPPER_INTERFACE_REFERENCE); - properties.setProperty("notEmpty", "false");//insert、update是否判断字符串类型!='' 即 test="str != null"表达式内是否追加 and str != '' + //insert、update是否判断字符串类型!='' 即 test="str != null"表达式内是否追加 and str != '' + properties.setProperty("notEmpty", "false"); properties.setProperty("IDENTITY", "MYSQL"); mapperScannerConfigurer.setProperties(properties); diff --git a/src/main/java/com/company/project/core/AbstractService.java b/src/main/java/com/company/project/core/AbstractService.java index 35dbf8201..1e8a0ee7e 100644 --- a/src/main/java/com/company/project/core/AbstractService.java +++ b/src/main/java/com/company/project/core/AbstractService.java @@ -17,33 +17,42 @@ public abstract class AbstractService implements Service { @Autowired protected Mapper mapper; - private Class modelClass; // 当前泛型真实类型的Class + /** + * 当前泛型真实类型的Class + */ + private Class modelClass; public AbstractService() { ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass(); modelClass = (Class) pt.getActualTypeArguments()[0]; } + @Override public void save(T model) { mapper.insertSelective(model); } + @Override public void save(List models) { mapper.insertList(models); } + @Override public void deleteById(Integer id) { mapper.deleteByPrimaryKey(id); } + @Override public void deleteByIds(String ids) { mapper.deleteByIds(ids); } + @Override public void update(T model) { mapper.updateByPrimaryKeySelective(model); } + @Override public T findById(Integer id) { return mapper.selectByPrimaryKey(id); } @@ -61,14 +70,17 @@ public T findBy(String fieldName, Object value) throws TooManyResultsException { } } + @Override public List findByIds(String ids) { return mapper.selectByIds(ids); } + @Override public List findByCondition(Condition condition) { return mapper.selectByCondition(condition); } + @Override public List findAll() { return mapper.selectAll(); } diff --git a/src/main/java/com/company/project/core/CustomObjectMapper.java b/src/main/java/com/company/project/core/CustomObjectMapper.java new file mode 100644 index 000000000..3ed0b51c7 --- /dev/null +++ b/src/main/java/com/company/project/core/CustomObjectMapper.java @@ -0,0 +1,58 @@ +package com.company.project.core; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import org.springframework.stereotype.Component; + +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.TimeZone; + +/** + * 定制 Jackson 的 ObjectMapper + * + * @author + * @since 1.0.0 + */ +@Component +public class CustomObjectMapper extends ObjectMapper { + + private static final long serialVersionUID = 1L; + + public CustomObjectMapper() { + super(); + init(); + } + + public void init() { + // 排除值为空属性,只对POJO起作用,map或者list无效 +// setSerializationInclusion(JsonInclude.Include.NON_NULL); + setSerializationInclusion(JsonInclude.Include.NON_EMPTY); + + // 是否进行缩进输出 + configure(SerializationFeature.INDENT_OUTPUT, false); + + // 将驼峰转为下划线 + // setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE); + + // 设置输入时忽略在JSON字符串中存在但Java对象实际没有的属性 + this.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); + this.setTimeZone(TimeZone.getDefault()); + + // 进行日期格式化 + String dateFormatPattern = "yyyy-MM-dd HH:mm:ss"; + this.setDateFormat(new SimpleDateFormat(dateFormatPattern)); + } + + + public String toJSONString(Object object) { + try { + return writeValueAsString(object); + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } +} diff --git a/src/main/java/com/company/project/core/ProjectConstant.java b/src/main/java/com/company/project/core/ProjectConstant.java deleted file mode 100644 index 76d6abe4c..000000000 --- a/src/main/java/com/company/project/core/ProjectConstant.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.company.project.core; - -/** - * 项目常量 - */ -public final class ProjectConstant { - public static final String BASE_PACKAGE = "com.company.project";//生成代码所在的基础包名称,可根据自己公司的项目修改(注意:这个配置修改之后需要手工修改src目录项目默认的包路径,使其保持一致,不然会找不到类) - - public static final String MODEL_PACKAGE = BASE_PACKAGE + ".model";//生成的Model所在包 - public static final String MAPPER_PACKAGE = BASE_PACKAGE + ".dao";//生成的Mapper所在包 - public static final String SERVICE_PACKAGE = BASE_PACKAGE + ".service";//生成的Service所在包 - public static final String SERVICE_IMPL_PACKAGE = SERVICE_PACKAGE + ".impl";//生成的ServiceImpl所在包 - public static final String CONTROLLER_PACKAGE = BASE_PACKAGE + ".web";//生成的Controller所在包 - - public static final String MAPPER_INTERFACE_REFERENCE = BASE_PACKAGE + ".core.Mapper";//Mapper插件基础接口的完全限定名 -} diff --git a/src/main/java/com/company/project/core/ProjectConstants.java b/src/main/java/com/company/project/core/ProjectConstants.java new file mode 100644 index 000000000..16c613a13 --- /dev/null +++ b/src/main/java/com/company/project/core/ProjectConstants.java @@ -0,0 +1,37 @@ +package com.company.project.core; + +/** + * 项目常量,除BASE_PACKAGE建议修改以外,别的常量均不建议修改 + * 因为这里修改后,在generator.template里面也需要再次修改引用包的路径 + */ +public final class ProjectConstants { + /** + * 生成代码所在的基础包名称,可根据自己公司的项目修改 + * (注意:这个配置修改之后需要手工修改src目录项目默认的包路径,使其保持一致,不然会找不到类) + */ + public static final String BASE_PACKAGE = "com.company.project"; + /** + * 生成的Model所在包 + */ + public static final String MODEL_PACKAGE = BASE_PACKAGE + ".model"; + /** + * 生成的Mapper所在包 + */ + public static final String MAPPER_PACKAGE = BASE_PACKAGE + ".dao"; + /** + * 生成的Service所在包 + */ + public static final String SERVICE_PACKAGE = BASE_PACKAGE + ".service"; + /** + * 生成的ServiceImpl所在包 + */ + public static final String SERVICE_IMPL_PACKAGE = SERVICE_PACKAGE + ".impl"; + /** + * 生成的Controller所在包 + */ + public static final String CONTROLLER_PACKAGE = BASE_PACKAGE + ".web"; + /** + * Mapper插件基础接口的完全限定名 + */ + public static final String MAPPER_INTERFACE_REFERENCE = BASE_PACKAGE + ".core.Mapper"; +} diff --git a/src/main/java/com/company/project/core/Result.java b/src/main/java/com/company/project/core/Result.java index 85ba3a114..a4f53d94c 100644 --- a/src/main/java/com/company/project/core/Result.java +++ b/src/main/java/com/company/project/core/Result.java @@ -1,7 +1,5 @@ package com.company.project.core; -import com.alibaba.fastjson.JSON; - /** * 统一API响应结果封装 */ @@ -36,9 +34,4 @@ public Result setData(T data) { this.data = data; return this; } - - @Override - public String toString() { - return JSON.toJSONString(this); - } } diff --git a/src/main/java/com/company/project/core/Service.java b/src/main/java/com/company/project/core/Service.java index 5fec7ca13..03e8a6a83 100644 --- a/src/main/java/com/company/project/core/Service.java +++ b/src/main/java/com/company/project/core/Service.java @@ -9,14 +9,75 @@ * Service 层 基础接口,其他Service 接口 请继承该接口 */ public interface Service { - void save(T model);//持久化 - void save(List models);//批量持久化 - void deleteById(Integer id);//通过主鍵刪除 - void deleteByIds(String ids);//批量刪除 eg:ids -> “1,2,3,4” - void update(T model);//更新 - T findById(Integer id);//通过ID查找 - T findBy(String fieldName, Object value) throws TooManyResultsException; //通过Model中某个成员变量名称(非数据表中column的名称)查找,value需符合unique约束 - List findByIds(String ids);//通过多个ID查找//eg:ids -> “1,2,3,4” - List findByCondition(Condition condition);//根据条件查找 - List findAll();//获取所有 + /** + * 持久化 + */ + void save(T model); + + /** + * 批量持久化 + */ + void save(List models); + + /** + * 通过主鍵刪除 + * + * @param id primary key + */ + void deleteById(Integer id); + + /** + * 批量刪除 + * + * @param ids eg:ids -> “1,2,3,4” + */ + void deleteByIds(String ids); + + /** + * 更新 + * + * @param model + */ + void update(T model); + + /** + * 通过ID查找 + * + * @param id + * @return + */ + T findById(Integer id); + + /** + * 通过Model中某个成员变量名称(非数据表中column的名称)查找,value需符合unique约束 + * + * @param fieldName fieldName + * @param value value + * @return + * @throws TooManyResultsException + */ + T findBy(String fieldName, Object value) throws TooManyResultsException; + + /** + * 通过多个ID查找//eg:ids -> “1,2,3,4” + * + * @param ids + * @return + */ + List findByIds(String ids); + + /** + * 根据条件查找 + * + * @param condition condition + * @return + */ + List findByCondition(Condition condition); + + /** + * 获取所有 + * + * @return + */ + List findAll(); } diff --git a/src/main/java/com/company/project/dao/UserTesterMapper.java b/src/main/java/com/company/project/dao/UserTesterMapper.java new file mode 100644 index 000000000..16fb22ef1 --- /dev/null +++ b/src/main/java/com/company/project/dao/UserTesterMapper.java @@ -0,0 +1,7 @@ +package com.company.project.dao; + +import com.company.project.core.Mapper; +import com.company.project.model.UserTester; + +public interface UserTesterMapper extends Mapper { +} \ No newline at end of file diff --git a/src/main/java/com/company/project/model/UserTester.java b/src/main/java/com/company/project/model/UserTester.java new file mode 100644 index 000000000..4b04a7b9a --- /dev/null +++ b/src/main/java/com/company/project/model/UserTester.java @@ -0,0 +1,148 @@ +package com.company.project.model; + +import java.util.Date; +import javax.persistence.*; + +@Table(name = "t_user_tester") +public class UserTester { + + /** 多个ID注解可以作为联合主键 */ + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Integer id; + + private String name; + + /** + * 0-关闭,1-正常 + */ + private String state; + + /** + * 创建时间 + */ + @Column(name = "create_time") + private Date createTime; + + @Column(name = "create_by") + private String createBy; + + /** + * 更新时间 + */ + @Column(name = "update_time") + private Date updateTime; + + @Column(name = "update_by") + private String updateBy; + + /** + * @return id + */ + public Integer getId() { + return id; + } + + /** + * @param id + */ + public void setId(Integer id) { + this.id = id; + } + + /** + * @return name + */ + public String getName() { + return name; + } + + /** + * @param name + */ + public void setName(String name) { + this.name = name; + } + + /** + * 获取0-关闭,1-正常 + * + * @return state - 0-关闭,1-正常 + */ + public String getState() { + return state; + } + + /** + * 设置0-关闭,1-正常 + * + * @param state 0-关闭,1-正常 + */ + public void setState(String state) { + this.state = state; + } + + /** + * 获取创建时间 + * + * @return create_time - 创建时间 + */ + public Date getCreateTime() { + return createTime; + } + + /** + * 设置创建时间 + * + * @param createTime 创建时间 + */ + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } + + /** + * @return create_by + */ + public String getCreateBy() { + return createBy; + } + + /** + * @param createBy + */ + public void setCreateBy(String createBy) { + this.createBy = createBy; + } + + /** + * 获取更新时间 + * + * @return update_time - 更新时间 + */ + public Date getUpdateTime() { + return updateTime; + } + + /** + * 设置更新时间 + * + * @param updateTime 更新时间 + */ + public void setUpdateTime(Date updateTime) { + this.updateTime = updateTime; + } + + /** + * @return update_by + */ + public String getUpdateBy() { + return updateBy; + } + + /** + * @param updateBy + */ + public void setUpdateBy(String updateBy) { + this.updateBy = updateBy; + } +} \ No newline at end of file diff --git a/src/main/java/com/company/project/service/UserTesterService.java b/src/main/java/com/company/project/service/UserTesterService.java new file mode 100644 index 000000000..f17ab700b --- /dev/null +++ b/src/main/java/com/company/project/service/UserTesterService.java @@ -0,0 +1,11 @@ +package com.company.project.service; +import com.company.project.model.UserTester; +import com.company.project.core.Service; + + +/** + * Created by CodeGenerator on 2019-04-09 09:43:40. + */ +public interface UserTesterService extends Service { + +} diff --git a/src/main/java/com/company/project/service/impl/UserTesterServiceImpl.java b/src/main/java/com/company/project/service/impl/UserTesterServiceImpl.java new file mode 100644 index 000000000..4d0ddd384 --- /dev/null +++ b/src/main/java/com/company/project/service/impl/UserTesterServiceImpl.java @@ -0,0 +1,22 @@ +package com.company.project.service.impl; + +import com.company.project.dao.UserTesterMapper; +import com.company.project.model.UserTester; +import com.company.project.service.UserTesterService; +import com.company.project.core.AbstractService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; + + +/** + * Created by CodeGenerator on 2019-04-09 09:43:40. + */ +@Service +@Transactional +public class UserTesterServiceImpl extends AbstractService implements UserTesterService { + @Resource + private UserTesterMapper tUserTesterMapper; + +} diff --git a/src/main/java/com/company/project/web/UserTesterController.java b/src/main/java/com/company/project/web/UserTesterController.java new file mode 100644 index 000000000..93b7ab77e --- /dev/null +++ b/src/main/java/com/company/project/web/UserTesterController.java @@ -0,0 +1,63 @@ +package com.company.project.web; +import com.company.project.core.CustomObjectMapper; +import com.company.project.core.Result; +import com.company.project.core.ResultGenerator; +import com.company.project.model.UserTester; +import com.company.project.service.UserTesterService; +import com.github.pagehelper.PageHelper; +import com.github.pagehelper.PageInfo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import java.util.List; + +/** +* Created by CodeGenerator on 2019-04-09 09:43:40. +*/ +@RestController +@RequestMapping("/user/tester") +public class UserTesterController { + private static final Logger LOGGER = LoggerFactory.getLogger(UserTesterController.class); + @Resource + private UserTesterService userTesterService; + @Resource + private CustomObjectMapper objectMapper; + + @PostMapping("/add") + public Result add(UserTester userTester) { + userTesterService.save(userTester); + return ResultGenerator.genSuccessResult(); + } + + @PostMapping("/delete") + public Result delete(@RequestParam Integer id) { + userTesterService.deleteById(id); + return ResultGenerator.genSuccessResult(); + } + + @PostMapping("/update") + public Result update(UserTester userTester) { + userTesterService.update(userTester); + return ResultGenerator.genSuccessResult(); + } + + @RequestMapping("/detail") + public Result detail(@RequestParam Integer id) { + UserTester userTester = userTesterService.findById(id); + return ResultGenerator.genSuccessResult(userTester); + } + + @RequestMapping("/list") + public Result list(@RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "0") Integer size) { + PageHelper.startPage(page, size); + List list = userTesterService.findAll(); + PageInfo pageInfo = new PageInfo(list); + LOGGER.info("返回到前端的数据=[{}]", objectMapper.toJSONString(pageInfo)); + return ResultGenerator.genSuccessResult(pageInfo); + } +} diff --git a/src/main/resources/application-dev.properties b/src/main/resources/application-dev.properties index 71aa3d9b0..b1e52e825 100644 --- a/src/main/resources/application-dev.properties +++ b/src/main/resources/application-dev.properties @@ -2,5 +2,8 @@ # 数据源配置,请修改为你项目的实际配置 spring.datasource.url=jdbc:mysql://localhost:3306/test spring.datasource.username=root -spring.datasource.password=123456 -spring.datasource.driver-class-name=com.mysql.jdbc.Driver +spring.datasource.password=root +spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver + +# 开发环境和生产环境的部署方式与本机不一样 +logging.config=config/logback-spring.xml \ No newline at end of file diff --git a/src/main/resources/application-test.properties b/src/main/resources/application-test.properties index 287da7b20..c39c5c4d3 100644 --- a/src/main/resources/application-test.properties +++ b/src/main/resources/application-test.properties @@ -1 +1,8 @@ # 测试环境配置 +# 数据源配置,请修改为你项目的实际配置 +spring.datasource.url=jdbc:mysql://localhost:3306/test +spring.datasource.username=root +spring.datasource.password=root +spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver + +logging.config=classpath:logback-spring.xml \ No newline at end of file diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index e217b7192..2dff4ca94 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,6 +1,13 @@ -spring.profiles.active=dev + # 所有环境通用的配置,放在这里 +server.port=7071 +# 根路径 +server.servlet.context-path=/seed +# 应用名称 +server.servlet.application-display-name=SEED +# 激活的配置文件 +spring.profiles.active=test # 404 交给异常处理器处理 spring.mvc.throw-exception-if-no-handler-found=true -spring.resources.add-mappings=false +spring.resources.add-mappings=false \ No newline at end of file diff --git a/src/main/resources/logback-spring.xml b/src/main/resources/logback-spring.xml new file mode 100644 index 000000000..0e91693d0 --- /dev/null +++ b/src/main/resources/logback-spring.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} \(L%line\) - %msg%n + + + + + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} \(L%line\) - %msg%n + + ${LOG_PATH}/${BASE_FILE_NAME}.log + + + ${LOG_PATH}/history/${BASE_FILE_NAME}.%d{yyyy-MM-dd}.%i.gz + ${LOG_FILE_MAX_SIZE} + ${LOG_FILE_MAX_HISTORY} + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/UserTesterMapper.xml b/src/main/resources/mapper/UserTesterMapper.xml new file mode 100644 index 000000000..e65a96e75 --- /dev/null +++ b/src/main/resources/mapper/UserTesterMapper.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/java/CodeGenerator.java b/src/test/java/CodeGenerator.java index 05928e2bf..92127ffc0 100644 --- a/src/test/java/CodeGenerator.java +++ b/src/test/java/CodeGenerator.java @@ -11,39 +11,72 @@ import java.text.SimpleDateFormat; import java.util.*; -import static com.company.project.core.ProjectConstant.*; +import static com.company.project.core.ProjectConstants.*; /** * 代码生成器,根据数据表名称生成对应的Model、Mapper、Service、Controller简化开发。 + * + * @author administrator + * @date 2019-04-09 */ public class CodeGenerator { - //JDBC配置,请修改为你项目的实际配置 + /** + * JDBC配置,请修改为你项目的实际配置 + */ private static final String JDBC_URL = "jdbc:mysql://localhost:3306/test"; private static final String JDBC_USERNAME = "root"; - private static final String JDBC_PASSWORD = "123456"; + private static final String JDBC_PASSWORD = "root"; private static final String JDBC_DIVER_CLASS_NAME = "com.mysql.jdbc.Driver"; - private static final String PROJECT_PATH = System.getProperty("user.dir");//项目在硬盘上的基础路径 - private static final String TEMPLATE_FILE_PATH = PROJECT_PATH + "/src/test/resources/generator/template";//模板位置 + /** + * 项目在硬盘上的基础路径 + */ + private static final String PROJECT_PATH = System.getProperty("user.dir"); + /** + * 模板位置 + */ + private static final String TEMPLATE_FILE_PATH = PROJECT_PATH + "/src/test/resources/generator/template"; - private static final String JAVA_PATH = "/src/main/java"; //java文件路径 - private static final String RESOURCES_PATH = "/src/main/resources";//资源文件路径 + /** + * java文件路径 + */ + private static final String JAVA_PATH = "/src/main/java"; + /** + * 资源文件路径 + */ + private static final String RESOURCES_PATH = "/src/main/resources"; - private static final String PACKAGE_PATH_SERVICE = packageConvertPath(SERVICE_PACKAGE);//生成的Service存放路径 - private static final String PACKAGE_PATH_SERVICE_IMPL = packageConvertPath(SERVICE_IMPL_PACKAGE);//生成的Service实现存放路径 - private static final String PACKAGE_PATH_CONTROLLER = packageConvertPath(CONTROLLER_PACKAGE);//生成的Controller存放路径 + /** + * 生成的Service存放路径 + */ + private static final String PACKAGE_PATH_SERVICE = packageConvertPath(SERVICE_PACKAGE); + /** + * 生成的Service实现存放路径 + */ + private static final String PACKAGE_PATH_SERVICE_IMPL = packageConvertPath(SERVICE_IMPL_PACKAGE); + /** + * 生成的Controller存放路径 + */ + private static final String PACKAGE_PATH_CONTROLLER = packageConvertPath(CONTROLLER_PACKAGE); - private static final String AUTHOR = "CodeGenerator";//@author - private static final String DATE = new SimpleDateFormat("yyyy/MM/dd").format(new Date());//@date + /** + * 作者信息 + */ + private static final String AUTHOR = "CodeGenerator"; + /** + * 时间 + */ + private static final String DATE = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()); public static void main(String[] args) { - genCode("输入表名"); - //genCodeByCustomModelName("输入表名","输入自定义Model名称"); +// genCode("输入表名"); + genCodeByCustomModelName("t_user_tester","UserTester"); } /** * 通过数据表名称生成代码,Model 名称通过解析数据表名称获得,下划线转大驼峰的形式。 * 如输入表名称 "t_user_detail" 将生成 TUserDetail、TUserDetailMapper、TUserDetailService ... + * * @param tableNames 数据表名称... */ public static void genCode(String... tableNames) { @@ -55,6 +88,7 @@ public static void genCode(String... tableNames) { /** * 通过数据表名称,和自定义的 Model 名称生成代码 * 如输入表名称 "t_user_detail" 和自定义的 Model 名称 "User" 将生成 User、UserMapper、UserService ... + * * @param tableName 数据表名称 * @param modelName 自定义的 Model 名称 */ @@ -102,7 +136,7 @@ public static void genModelAndMapper(String tableName, String modelName) { TableConfiguration tableConfiguration = new TableConfiguration(context); tableConfiguration.setTableName(tableName); - if (StringUtils.isNotEmpty(modelName))tableConfiguration.setDomainObjectName(modelName); + if (StringUtils.isNotEmpty(modelName)) tableConfiguration.setDomainObjectName(modelName); tableConfiguration.setGeneratedKey(new GeneratedKey("id", "Mysql", true, null)); context.addTableConfiguration(tableConfiguration); diff --git a/src/test/java/com/conpany/project/Tester.java b/src/test/java/com/conpany/project/Tester.java index ca247abae..9630090ba 100644 --- a/src/test/java/com/conpany/project/Tester.java +++ b/src/test/java/com/conpany/project/Tester.java @@ -1,7 +1,7 @@ package com.conpany.project; -import com.company.project.Application; +import com.company.project.AppStarter; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.annotation.Rollback; @@ -12,7 +12,7 @@ * 单元测试继承该类即可 */ @RunWith(SpringRunner.class) -@SpringBootTest(classes = Application.class) +@SpringBootTest(classes = AppStarter.class) @Transactional @Rollback public abstract class Tester {} diff --git a/src/test/resources/demo-user.sql b/src/test/resources/demo-user.sql index 6c16772ff..76d35e3f1 100644 --- a/src/test/resources/demo-user.sql +++ b/src/test/resources/demo-user.sql @@ -2,44 +2,37 @@ Navicat MySQL Data Transfer Source Server : Localhost -Source Server Version : 50713 +Source Server Version : 50721 Source Host : localhost:3306 Source Database : test Target Server Type : MYSQL -Target Server Version : 50713 +Target Server Version : 50721 File Encoding : 65001 -Date: 2017-06-23 14:25:27 +Date: 2019-04-10 15:53:02 */ SET FOREIGN_KEY_CHECKS=0; -- ---------------------------- --- Table structure for user +-- Table structure for t_user_tester -- ---------------------------- -DROP TABLE IF EXISTS `user`; -CREATE TABLE `user` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `username` varchar(255) NOT NULL, - `password` varchar(255) NOT NULL, - `nick_name` varchar(255) DEFAULT NULL, - `sex` int(1) DEFAULT NULL, - `register_date` datetime NOT NULL, +DROP TABLE IF EXISTS `t_user_tester`; +CREATE TABLE `t_user_tester` ( + `id` int(10) NOT NULL AUTO_INCREMENT, + `name` varchar(255) DEFAULT NULL, + `state` char(1) DEFAULT '1' COMMENT '0-关闭,1-正常', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `create_by` varchar(64) DEFAULT NULL, + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `update_by` varchar(64) DEFAULT NULL, PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; +) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8; -- ---------------------------- --- Records of user +-- Records of t_user_tester -- ---------------------------- -INSERT INTO `user` VALUES ('1', '89921218@qq.com', '1ee04e0b1cb5af7367c80c22e42efd8b', '土豆', '1', '2017-06-23 14:24:23'); -INSERT INTO `user` VALUES ('2', '2@qq.com', '1ee04e0b1cb5af7367c80c22e42efd8b', '土豆-2', '1', '2017-06-23 14:24:23'); -INSERT INTO `user` VALUES ('3', '3@qq.com', '1ee04e0b1cb5af7367c80c22e42efd8b', '土豆-3', '1', '2017-06-23 14:24:23'); -INSERT INTO `user` VALUES ('4', '4@qq.com', '1ee04e0b1cb5af7367c80c22e42efd8b', '土豆-4', '1', '2017-06-23 14:24:23'); -INSERT INTO `user` VALUES ('5', '5@qq.com', '1ee04e0b1cb5af7367c80c22e42efd8b', '土豆-5', '1', '2017-06-23 14:24:23'); -INSERT INTO `user` VALUES ('6', '6@qq.com', '1ee04e0b1cb5af7367c80c22e42efd8b', '土豆-6', '1', '2017-06-23 14:24:23'); -INSERT INTO `user` VALUES ('7', '7@qq.com', '1ee04e0b1cb5af7367c80c22e42efd8b', '土豆-7', '1', '2017-06-23 14:24:23'); -INSERT INTO `user` VALUES ('8', '8@qq.com', '1ee04e0b1cb5af7367c80c22e42efd8b', '土豆-8', '1', '2017-06-23 14:24:23'); -INSERT INTO `user` VALUES ('9', '9@qq.com', '1ee04e0b1cb5af7367c80c22e42efd8b', '土豆-9', '1', '2017-06-23 14:24:23'); -INSERT INTO `user` VALUES ('10', '10@qq.com', '1ee04e0b1cb5af7367c80c22e42efd8b', '土豆-10', '1', '2017-06-23 14:24:23'); -SET FOREIGN_KEY_CHECKS=1; +INSERT INTO `t_user_tester` VALUES ('1', 'jcouyang', '1', '2019-04-09 09:53:21', 'admin', null, null); +INSERT INTO `t_user_tester` VALUES ('2', '123243', '1', '2019-04-09 09:56:15', 'jcouyang', null, null); +INSERT INTO `t_user_tester` VALUES ('3', '123', '1', '2019-04-10 15:20:30', '中文测试', null, null);