jdk8+,开发软件idea,关系型数据库mysql(持久型),非关系型数据库redis(缓存)
file -> new -> Project 选择Maven看到如下界面:
点击next, 出现:
填写GroupId 和 ArtifactId,然后点击next, 然后点finish
org.springframework.boot
spring-boot-starter-parent
2.1.3.RELEASE
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-aop
org.springframework.boot
spring-boot-starter
org.springframework.boot
spring-boot-starter-data-redis
org.springframework.boot
spring-boot-starter
org.apache.commons
commons-pool2
2.6.0
mysql
mysql-connector-java
5.1.35
runtime
com.zaxxer
HikariCP
org.springframework.boot
spring-boot-starter-jdbc
tk.mybatis
mapper-spring-boot-starter
2.1.0
com.github.pagehelper
pagehelper-spring-boot-starter
1.2.5
io.springfox
springfox-swagger-ui
2.9.2
io.springfox
springfox-swagger2
2.9.2
io.swagger
swagger-models
1.5.21
org.projectlombok
lombok
1.18.0
provided
org.springframework.boot
spring-boot-maven-plugin
org.mybatis.generator
mybatis-generator-maven-plugin
1.3.5
true
true
${basedir}/src/main/resources/mybatis/generator/mybatis-generator.xml
mysql
mysql-connector-java
5.1.35
runtime
tk.mybatis
mapper
3.5.3
org.mybatis.generator
mybatis-generator-core
1.3.5
##连接mysql关系数据库配置
#spring.datasource.druid.url=jdbc:mysql://localhost:3306/cloudrises?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true
#spring.datasource.druid.driver-class-name=com.mysql.jdbc.Driver
#spring.datasource.druid.username=root
#spring.datasource.druid.password=root
#####com.alibaba.druid.pool.DruidDataSource 连接池 阿里巴巴数据源
#spring.datasource.druid.db-type=mysql
#spring.datasource.druid.max-active=10
#spring.datasource.druid.min-idle=1
#spring.datasource.druid.max-wait=30000
#spring.datasource.druid.use-unfair-lock=true
#spring.datasource.druid.pool-prepared-statements=false
#### Hikaricp数据库连接池 对于web项目,要配置:destroy-method="shutdown"
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
spring.datasource.url=jdbc:mysql://localhost:3306/cloudrises?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true
spring.datasource.username=root
spring.datasource.password=root
## 驱动
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
## 数据源只读配置(默认false)
spring.datasource.hikari.read-only=false
## 连接超时时间(默认30秒)
spring.datasource.hikari.connection-timeout=30000
## 空闲超时时间,只有在minimumIdle
logback
%d{yyyy-MM-dd HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} - %msg%n
${log.file}
${log.path}%d{yyyy-MM-dd_HH}.log
30
1GB
%d{yyyy-MM-dd HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} - %msg%n
package com.study.advice;
import com.study.enums.ResponseResultEnums;
import com.study.exceptions.CustomizeException;
import com.study.response.HttpResponse;
import org.apache.ibatis.session.SqlSessionException;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolationException;
import java.util.Calendar;
/**
* 全局异常判断
*/
@ControllerAdvice
public class GolbalException {
@ResponseBody
@ExceptionHandler(Exception.class)
public HttpResponse handleExceptions(HttpServletRequest request, HttpServletResponse response, Exception e){
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json; charset = utf-8");
Calendar calendar=Calendar.getInstance();
String message = "";
String code = ResponseResultEnums.ERROR.getCode();
if (e instanceof NullPointerException){// 空指针异常
message = "空指针异常";
}else if(e instanceof HttpMediaTypeNotSupportedException){// 请求类型出错
message = "不支持的内容格式出错";
}else if (e instanceof MethodArgumentNotValidException){//swagger2注解判断抛出的异常
MethodArgumentNotValidException me = (MethodArgumentNotValidException)e;
message=me.getBindingResult().getAllErrors().get(0).getDefaultMessage();
}else if (e instanceof IllegalArgumentException){
IllegalArgumentException ie = (IllegalArgumentException) e;
message = ie.getMessage();
}else if (e instanceof SqlSessionException){// 数据库操作出错
SqlSessionException se = (SqlSessionException)e;
message = se.getMessage();
}else if (e instanceof HttpRequestMethodNotSupportedException){
HttpRequestMethodNotSupportedException he = (HttpRequestMethodNotSupportedException)e;
message = he.getMessage();
} else if (e instanceof ConstraintViolationException){// notnull等注解会出现的异常
ConstraintViolationException me = (ConstraintViolationException)e;
message=me.getMessage();
}else if (e instanceof CustomizeException){
CustomizeException ce = (CustomizeException)e;
code = ce.getCode();
message = ce.getMessage();
}else {
message = "发生全局异常";
}
System.out.println(calendar.getTime()+" : "+this.getClass().getName()+" : "+message);
e.printStackTrace();
return HttpResponse.success(code,message);
}
}
package com.study.advice;
import lombok.extern.log4j.Log4j2;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
@Aspect
@Component
@Log4j2
public class MvcMethodLogAdvice {
@Resource
private HttpServletRequest request;
@Before("@annotation(org.springframework.web.bind.annotation.PostMapping)" +
"||@annotation(org.springframework.web.bind.annotation.RequestMapping)" +
"||@annotation(org.springframework.web.bind.annotation.GetMapping)")
public void beforeAdvice(JoinPoint joinPoint) {
printMethodParams(joinPoint);
}
/**
* @param point
* @description 打印方法的参数名和参数值
*/
public void printMethodParams(JoinPoint point) {
if (point == null) {
return;
}
// Signature 包含了方法名、申明类型以及地址等信息
// String className = point.getTarget().getClass().getName();
// String methodName = point.getSignature().getName();
// 获取方法的参数值数组。
Object[] method_args = point.getArgs();
// 获取方法参数名称
String[] paramNames = ((MethodSignature) point.getSignature()).getParameterNames();
logParam(paramNames, method_args);
}
/**
* @param paramsArgsName 方法参数名数组
* @param paramsArgsValue 方法参数值数组
* @description 打印方法的参数名和参数值, 基本类型直接打印, 非基本类型需要重写toString方法
*/
private void logParam(String[] paramsArgsName, Object[] paramsArgsValue) {
if ((paramsArgsName == null || paramsArgsName.length <= 0) ||
(paramsArgsValue == null || paramsArgsValue.length <= 0)) {
log.info("url=[" + request.getRequestURL() + "]无请求参数");
return;
}
StringBuffer buffer = new StringBuffer();
buffer.append("{ ");
for (int i = 0; i < paramsArgsName.length; i++) {
String name = paramsArgsName[i];
if (name.equals("session")) {
continue;
}
Object value = paramsArgsValue[i];
buffer.append(name + " : ");
if (null == value) {
buffer.append(null + " ,");
} else if (isPrimite(value.getClass())) {
buffer.append(value + " ,");
} else {
buffer.append(value.toString() + " ,");
}
}
String logString = buffer.toString();
if (logString.contains(",")) {
logString = logString.substring(0, logString.lastIndexOf(","));
}
// buffer.deleteCharAt(buffer.lastIndexOf(","));
// buffer.append("}");
logString += "}";
log.info("url=[" + request.getRequestURL() + "]请求参数为: \033[35;0m" + logString + "\033[0m");
}
/**
* @param clazz
* @return
* @description 判断是否为基本类型:包括String
*/
private boolean isPrimite(Class> clazz) {
if (clazz.isPrimitive() || clazz == String.class) {
return true;
} else {
return false;
}
}
}
package com.study.advice;
import com.study.utils.JsonUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import lombok.extern.log4j.Log4j2;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
@Log4j2
@ControllerAdvice(basePackages = "com.study")
public class LogResponseAdvice implements ResponseBodyAdvice
package com.study.common;
import tk.mybatis.mapper.annotation.RegisterMapper;
import tk.mybatis.mapper.common.ExampleMapper;
import tk.mybatis.mapper.common.IdsMapper;
import tk.mybatis.mapper.common.Mapper;
import tk.mybatis.mapper.common.MySqlMapper;
/**
* @author lzr
* @date 2019/3/26 0026 09:38
*/
@RegisterMapper
public interface BaseMapper extends Mapper, MySqlMapper, IdsMapper, ExampleMapper {
}
package com.study.common;
import lombok.Data;
import lombok.ToString;
import java.io.Serializable;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Data
@ToString
public class BasePage implements Serializable {
/**
* 每页条数
*/
private Integer pageSize = 10;
/**
* 当前页数
*/
private Integer pageNum = 1;
/**
* 排序字段
*/
private String orderField;
/**
* 正序还是倒序
*/
private String order;
public String createOrderSql() {
if (this.orderField != null) {
return camelToUnderline(new StringBuffer(this.orderField)).append(" " + order).toString();
}
return "";
}
/**
* 下划线转驼峰
*
* @param str
* @return
*/
public static StringBuffer underlineToCamel(StringBuffer str) {
//利用正则删除下划线,把下划线后一位改成大写
Pattern pattern = Pattern.compile("_(\\w)");
Matcher matcher = pattern.matcher(str);
StringBuffer sb = new StringBuffer(str);
if (matcher.find()) {
sb = new StringBuffer();
//将当前匹配子串替换为指定字符串,并且将替换后的子串以及其之前到上次匹配子串之后的字符串段添加到一个StringBuffer对象里。
//正则之前的字符和被替换的字符
matcher.appendReplacement(sb, matcher.group(1).toUpperCase());
//把之后的也添加到StringBuffer对象里
matcher.appendTail(sb);
} else {
return sb;
}
return underlineToCamel(sb);
}
/**
* 驼峰转下划线
*
* @param str
* @return
*/
private static StringBuffer camelToUnderline(StringBuffer str) {
Pattern pattern = Pattern.compile("[A-Z]");
Matcher matcher = pattern.matcher(str);
StringBuffer sb = new StringBuffer(str);
if (matcher.find()) {
sb = new StringBuffer();
//将当前匹配子串替换为指定字符串,并且将替换后的子串以及其之前到上次匹配子串之后的字符串段添加到一个StringBuffer对象里。
//正则之前的字符和被替换的字符
matcher.appendReplacement(sb, "_" + matcher.group(0).toLowerCase());
//把之后的也添加到StringBuffer对象里
matcher.appendTail(sb);
} else {
return sb;
}
return camelToUnderline(sb);
}
}
package com.study.common;
import com.github.pagehelper.Page;
import lombok.Data;
import lombok.ToString;
import java.util.List;
@Data
@ToString
public class PageResult {
public PageResult(Page page) {
this.pageNum = page.getPageNum();
this.pageSize = page.getPageSize();
this.total = page.getTotal();
this.pages = page.getPages();
this.result = page.getResult();
}
/**
* 当前页数
*/
private Integer pageNum;
/**
* 每页条数
*/
private Integer pageSize;
/**
* 总条数
*/
private long total;
/**
* 总页数
*/
private Integer pages;
/**
* 数据
*/
private List result;
}
package com.study.config;
import com.study.exceptions.MyAsyncUncaughtExceptionHandler;
import lombok.extern.log4j.Log4j2;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
/**
* 自定义线程池 (java的异步,常用于多线程开发)
* 异步线程池配置
* @Async注解无效的可能点:
* 1、异步方法使用static修饰
* 2、异步类没有使用@Component注解(或其他注解)导致spring无法扫描到异步类
* 3、测试异步方法不能与异步方法在同一个类中
* 4、测试类中需要使用@Autowired或@Resource等注解自动注入,不能自己手动new对象
* 5、如果使用SpringBoot框架必须在启动类中增加@EnableAsync注解
*/
@Configuration
@Log4j2
public class AsyncConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);// 最小线程数为10(核心线程池大小)
executor.setMaxPoolSize(100);// 最大线程数为100
executor.setQueueCapacity(100);// 队列最大数量为100
executor.setKeepAliveSeconds(20);// 当线程空闲20秒(活跃时间,默认情况下是60秒)时回收线程时
executor.setThreadNamePrefix("cloudrises-async-schedule-");// 线程的前置名称
// setRejectedExecutionHandler:当pool已经达到max size的时候,如何处理新任务
// CallerRunsPolicy:不在新线程中执行任务,而是由调用者所在的线程来执行
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
//如果不初始化,导致找到不到执行器
executor.initialize();
return executor;
}
/**
* 异步任务中处理异常
*/
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new MyAsyncUncaughtExceptionHandler();
}
}
package com.study.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisConfiguration {
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
// 使用Jackson2JsonRedisSerialize 替换默认序列化
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
// 设置value的序列化规则和 key的序列化规则
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setKeySerializer(new StringRedisSerializer());// 定义key序列化
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
package com.study.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@Configuration
@EnableSwagger2
//@ConditionalOnProperty(prefix = "swagger2",value = {"enable"},havingValue = "true")
public class Swagger2 {
// swagger2.enable是application中的配置(自己添加"swagger2.enable=true")
@Value("${swagger2.enable}")
private boolean externallyConfiguredFlag;
//swagger2的配置文件,这里可以配置swagger2的一些基本的内容,比如扫描的包等等
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.enable(externallyConfiguredFlag)
.apiInfo(apiInfo())
.select()
//为当前包路径
.apis(RequestHandlerSelectors.basePackage("com.cloudrises.projectframework.logic.controller"))
.paths(PathSelectors.any())
.build();
}
//构建 api文档的详细信息函数,注意这里的注解引用的是哪个
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
//页面标题
.title("工程项目请求路径")
//创建人
.contact(new Contact("柳正润", "http://www.baidu.com", "[email protected]"))
//版本号
.version("1.0")
//描述
.description("项目框架")
.build();
}
}
package com.study.enums;
/**
* @author lzr
* @date 2019/3/27 0027 14:48
*/
public enum ResponseResultEnums {
SUCCESS("1","请求成功"),
FAIL("-1","请求失败"),
ERROR("-9","系统错误");
private String code;// code码
private String msg;// 消息
ResponseResultEnums(String code, String msg){this.code=code;this.msg=msg;}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
package com.study.exceptions;
import com.study.enums.ResponseResultEnums;
import lombok.Data;
/**
* @author lzr
* @date 2019/5/13 0013 17:01
*/
@Data
public class CustomizeException extends RuntimeException{
private String code;
public CustomizeException(String message) {
super(message);
}
public CustomizeException(String code, String message) {
super(message);
this.code = code;
}
public CustomizeException(ResponseResultEnums responseResultEnums){
super(responseResultEnums.getMsg());
this.code = responseResultEnums.getCode();
}
}
package com.study.exceptions;
import lombok.extern.log4j.Log4j2;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import java.lang.reflect.Method;
/**
* 异步操作,异常处理
* lzr
* MyAsyncUncaughtExceptionHandler
*/
@Log4j2
public class MyAsyncUncaughtExceptionHandler implements AsyncUncaughtExceptionHandler {
@Override
public void handleUncaughtException(Throwable ex, Method method, Object... params) {
log.error("ex=",ex,",方法名称",method.getName(),",参数",params.toString());
}
}
package com.study.response;
import com.study.exceptions.CustomizeException;
import com.study.enums.ResponseResultEnums;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.io.Serializable;
/**
* @author lzr
* @date 2019/11/11 0027 14:28
*/
@Data
@AllArgsConstructor
public class HttpResponse implements Serializable {
private String code;
private String msg;
private Object data;
public static HttpResponse success() {
return success(null);
}
public static HttpResponse success(Object data) {
return success(ResponseResultEnums.SUCCESS.getCode(), ResponseResultEnums.SUCCESS.getMsg(), data);
}
public static HttpResponse success(String code, String msg) {
return success(code, msg, null);
}
public static HttpResponse success(String msg, Object data) {
return success(ResponseResultEnums.SUCCESS.getCode(), msg, data);
}
private static HttpResponse success(String code, String msg, Object data) {
return new HttpResponse(code, msg, data);
}
public static HttpResponse fail(String code, String msg) {
throw new CustomizeException(code,msg);
}
public static HttpResponse fail(String msg){
throw new CustomizeException(ResponseResultEnums.FAIL.getCode(), msg);
}
public static HttpResponse fail(ResponseResultEnums responseResultEnums){
throw new CustomizeException(responseResultEnums.getCode(),responseResultEnums.getMsg());
}
public static HttpResponse fail(){
throw new CustomizeException(ResponseResultEnums.FAIL);
}
/**
* 只用于过滤器 返回数据
*/
public static HttpResponse filterData(ResponseResultEnums responseResultEnums){
return HttpResponse.success(responseResultEnums.getCode(),responseResultEnums.getMsg());
}
}
package com.study.utils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.log4j.Log4j2;
import javax.servlet.ServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
@Log4j2
public class JsonUtils {
public static ObjectMapper objectMapper = new ObjectMapper();
public static String Object2json(Object object) throws JsonProcessingException {
return objectMapper.writeValueAsString(object);
}
public static T json2Object(String json, Class valueType) throws IOException {
return objectMapper.readValue(json, valueType);
}
}
package com.study;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author lzr
* @date 2019/11/11 0011 17:18
*/
@MapperScan("com.study.dao")// 扫描mapper接口文件,注意引入的包是:“tk.mybatis.spring.annotation.MapperScan”
@EnableScheduling// 开启定时器线程
@EnableAsync// 开启异步操作
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class,args);
}
}
[email protected]:liuzhengrun/study_singleframework.git
若有疑问,请在评论区留言,谢谢