SpringBoot连接方式
1.常见spring.datasource.url
2.jndi方式链接spring.datasource.jndi–name:java/comp/env/jdbc/sampleds
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/light?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=GMT%2B81 spring.datasource.username=root spring.datasource.password=root spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
SpringBoot使用yml方式配置
spring:
datasource:
url:(空格)jdbc:mysql://127.0.0.1:3306/light?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=GMT%2B8
Springboot中Mybatis的配置方式
mybatis.type-aliases-package=com.crystal.light.entity
mybatis.config-locations=classpath:mybatis/mybatis-config.xml
mybatis.mapper-locations=classpath:mybatis/mapper/*.xml
Springboot开启事务注解
@EnableTransactionalManagement 开启事务
@Transactional 声明事务
允许自定义事务
在Application中增加
@Bean
public PlatformTransactionalManager txManage(DataSource datasource){`
return new DataSourceTransactionalManager(datasource);`
}
如何在SpringBoot中引入springboot MVC
1.在Application extends SpringBootServletInitializer
2.重写SpringBootServletInitializer的configure方法
protected SpringApplicationBuilder configure(SpringApplicationBuilder application){
return application.sources(Application.class);
}
Springboot处理全局Exception:
类上加入注解@ControllerAdvice 定义controller切面
方法上加入注解@ExceptionHandler(value = Exception.class)说明需要拦截的Exception
SpringBoot常用配置:
########################################################
###EMBEDDED SERVER CONFIGURATION (ServerProperties)
########################################################
#server.port=8080
#server.address= # bind to a specific NIC
#server.session-timeout= # session timeout in seconds
#the context path, defaults to '/'
#server.context-path=/spring-boot
#server.servlet-path= # the servlet path, defaults to '/'
#server.tomcat.access-log-pattern= # log pattern of the access log
#server.tomcat.access-log-enabled=false # is access logging enabled
#server.tomcat.protocol-header=x-forwarded-proto # ssl forward headers
#server.tomcat.remote-ip-header=x-forwarded-for
#server.tomcat.basedir=/tmp # base dir (usually not needed, defaults to tmp)
#server.tomcat.background-processor-delay=30; # in seconds
#server.tomcat.max-threads = 0 # number of threads in protocol handler
#server.tomcat.uri-encoding = UTF-8 # character encoding to use for URL decoding
SpringBoot开启定时任务:
在主程序Application上添加注解@EnableScheduling开启定时任务的支持
在每个类方法上加入@Schedule(cron="")进行定时调用
cron:例子 0/5 * * * * ?(秒 分 时 日 月 年)
静态资源和添加拦截器等方法
WebMvcConfigurationSupport和WebMvcConfigurerAdapter
WebMvcConfigurerAdapter为已过时的类
WebMvcConfigurationSupport为用于替代的新类
添加拦截器(重写addInterceptors方法,可添加多个):
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(logInterceptor()).addPathPatterns(adminPath + "/**")
.excludePathPatterns(adminPath + "/", adminPath + "/login", adminPath + "/sys/menu/tree", adminPath + "/sys/menu/treeData",
adminPath + "/oa/oaNotify/self/count");
}
拦截器需继承LoginInterceptor implements HandlerInterceptor,并重写
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
}
三个方法,且只有prehandle返回true时才会执行postHandle和after…
SpringBoot使用注解标注过滤器
@WebFilter将一个实现了javax.servlet.Filter接口的类定义为过滤器
属性filterName声明过滤器的名称
属性urlPatterns指定要过滤的URL模式,也可使用属性value来声明(指定要过滤的URL模式是必选属性)
@WebFilter(filterName="myFilter",urlPatterns="/*")
拦截器和过滤器的原理
(1)、Filter需要在web.xml中配置,依赖于Servlet;
(2)、Interceptor需要在SpringMVC中配置,依赖于框架;
(3)、Filter的执行顺序在Interceptor之前,具体的流程见下图
doFilter -> DispatcherServlet加载 -> Interceptor prehandle -> controller执行 -> Interceptor posthandle
-> view层渲染加载 -> Interceptor afterCompletion -> doFilter after
(4)、多个Filter之间以web.xml中加载顺序为先后顺序,多个Interceptor中Spring容器内配置顺序为先后顺序,多个拦截器先调用的先执行preHandle,但是后执行postHandle和afterCompletion
(5)、拦截器不可以修改request的任何内容,但是能抛出异常或者返回false暂停Request的执行
spring boot拦截器中获取request post请求中的参数
调用request.getInputStream()获取流,然后从流中读取参数,如下代码所示:
String body = "";
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = null;
InputStream inputStream = null;
try {
inputStream = request.getInputStream();
if (inputStream != null) {
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
char[] charBuffer = new char[128];
int bytesRead = -1;
while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
stringBuilder.append(charBuffer, 0, bytesRead);
}
} else {
stringBuilder.append("");
}
} catch (IOException ex) {
e.printStackTrace();
} finally {
if (inputStream != null) {
try {
inputStream.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
if (bufferedReader != null) {
try {
bufferedReader.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
body = stringBuilder.toString();
代码中的body就是request中的参数,我这里传的是JSON数据:{“page”: 1, “pageSize”: 10},那么body就是:body = “{“page”: 1, “pageSize”: 10}”,一个JSON字符串。这样是可以成功获取到post请求的body,但是,经过拦截器后,参数经过@RequestBody注解赋值给controller中的方法的时候,却抛出了一个这样的异常:
org.springframework.http.converter.HttpMessageNotReadableException: Required request body is missing
在网上查找资料后发现,request的输入流只能读取一次,那么这是为什么呢?下面是答案:那是因为流对应的是数据,数据放在内存中,有的是部分放在内存中。read 一次标记一次当前位置(mark position),第二次read就从标记位置继续读(从内存中copy)数据。 所以这就是为什么读了一次第二次是空了。 怎么让它不为空呢?只要inputstream 中的pos 变成0就可以重写读取当前内存中的数据。javaAPI中有一个方法public void reset() 这个方法就是可以重置pos为起始位置,但是不是所有的IO读取流都可以调用该方法!ServletInputStream是不能调用reset方法,这就导致了只能调用一次getInputStream()。
那么有什么办法可以用户解决呢?上面这篇博客中提到了解决方案,就是重写HttpServletRequestWrapper把request保存下来,然后通过过滤器把保存下来的request再填充进去,这样就可以多次读取request了。步骤如下所示:
①写一个类,继承HttpServletRequestWrapper
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
public class RequestWrapper extends HttpServletRequestWrapper {
private final String body;
public RequestWrapper(HttpServletRequest request) {
super(request);
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = null;
InputStream inputStream = null;
try {
inputStream = request.getInputStream();
if (inputStream != null) {
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
char[] charBuffer = new char[128];
int bytesRead = -1;
while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
stringBuilder.append(charBuffer, 0, bytesRead);
}
} else {
stringBuilder.append("");
}
} catch (IOException ex) {
} finally {
if (inputStream != null) {
try {
inputStream.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
if (bufferedReader != null) {
try {
bufferedReader.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
body = stringBuilder.toString();
}
@Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes());
ServletInputStream servletInputStream = new ServletInputStream() {
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
}
@Override
public int read() throws IOException {
return byteArrayInputStream.read();
}
};
return servletInputStream;
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
public String getBody() {
return this.body;
}
}
②拦截器层面
import com.alibaba.fastjson.JSON;
import com.miniprogram.api.douyin.user.req.DyuserReq;
import com.miniprogram.common.auth.VisitLimitCount;
import com.miniprogram.common.cache.RedisCache;
import com.miniprogram.common.config.InterceptorConfigMap;
import com.miniprogram.common.config.InterceptorUrlConfig;
import com.miniprogram.common.douyin.SearchEngineMapConstants;
import com.miniprogram.common.response.Response;
import com.miniprogram.common.session.*;
import com.miniprogram.common.utils.DateUtil;
import com.miniprogram.dao.common.UserLoginEntity.Users;
import com.miniprogram.service.douyin.users.UsersService;
import com.miniprogram.web.douyin.config.RequestWrapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Component("authSecurityInterceptor")
public class AuthSecurityInterceptor extends HandlerInterceptorAdapter {
private Logger logger = LoggerFactory.getLogger(AuthSecurityInterceptor.class);
@Autowired
private RedisCache redisCache;
@Autowired
private VisitLimitCount visitLimitCount;
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
try {
RequestWrapper requestWrapper = new RequestWrapper(httpServletRequest);
String body = requestWrapper.getBody();
System.out.println(body);
return true;
}catch (Exception e){
logger.error("权限判断出错",e);
}
return false;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
}
}
③过滤器Filter,用来把request传递下去
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
@WebFilter(urlPatterns = "/*",filterName = "channelFilter")
public class ChannelFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
ServletRequest requestWrapper = null;
if(servletRequest instanceof HttpServletRequest) {
requestWrapper = new RequestWrapper((HttpServletRequest) servletRequest);
}
if(requestWrapper == null) {
filterChain.doFilter(servletRequest, servletResponse);
} else {
filterChain.doFilter(requestWrapper, servletResponse);
}
}
@Override
public void destroy() {
}
}
④在启动类中注册拦截器
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.MultipartConfigFactory;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@SpringBootApplication
// @ServletComponentScan //注册过滤器注解
@Configuration
public class WebApplication {
public static void main(String[] args) {
SpringApplication.run(WebApplication.class, args);
}
}
SpringBoot和Spring配置线程池
配置SpringBoot线程池
SpringBootApplication启动类上需要加入注解@EnableAsync或者在配置类上使用
@Configuration
@EnableAsync
public class ExecutorConfig {
private static final Logger logger = LoggerFactory.getLogger(ExecutorConfig.class);
@Bean
public Executor asyncServiceExecutor() {
logger.info("start asyncServiceExecutor");
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//配置核心线程数
executor.setCorePoolSize(5);
//配置最大线程数
executor.setMaxPoolSize(5);
//配置队列大小
executor.setQueueCapacity(99999);
//配置线程池中的线程的名称前缀
executor.setThreadNamePrefix("async-service-");
// rejection-policy:当pool已经达到max size的时候,如何处理新任务
// CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
//执行初始化
executor.initialize();
return executor;
}
}
扩展实现检测线程池
public class VisiableThreadPoolTaskExecutor extends ThreadPoolTaskExecutor {
private static final Logger logger = LoggerFactory.getLogger(VisiableThreadPoolTaskExecutor.class);
private void showThreadPoolInfo(String prefix){
ThreadPoolExecutor threadPoolExecutor = getThreadPoolExecutor();
if(null==threadPoolExecutor){
return;
}
logger.info("{}, {},taskCount [{}], completedTaskCount [{}], activeCount [{}], queueSize [{}]",
this.getThreadNamePrefix(),
prefix,
threadPoolExecutor.getTaskCount(),
threadPoolExecutor.getCompletedTaskCount(),
threadPoolExecutor.getActiveCount(),
threadPoolExecutor.getQueue().size());
}
@Override
public void execute(Runnable task) {
showThreadPoolInfo("1. do execute");
super.execute(task);
}
@Override
public void execute(Runnable task, long startTimeout) {
showThreadPoolInfo("2. do execute");
super.execute(task, startTimeout);
}
@Override
public Future<?> submit(Runnable task) {
showThreadPoolInfo("1. do submit");
return super.submit(task);
}
@Override
public <T> Future<T> submit(Callable<T> task) {
showThreadPoolInfo("2. do submit");
return super.submit(task);
}
@Override
public ListenableFuture<?> submitListenable(Runnable task) {
showThreadPoolInfo("1. do submitListenable");
return super.submitListenable(task);
}
@Override
public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
showThreadPoolInfo("2. do submitListenable");
return super.submitListenable(task);
}
}
SpringBoot中使用theamleaf和freemarker
1.theamleaf
<!-- 引入theamleaf包 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
#application.properties中加入配置关闭theamleaf缓存机制
spring.thymeleaf.cache=false
2.freemarker
<!-- 引入freemarker包 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
#application.properties中加入配置
########################################################
###FREEMARKER (FreeMarkerAutoConfiguration)
########################################################
spring.freemarker.allow-request-override=false
spring.freemarker.cache=true
spring.freemarker.check-template-location=true
spring.freemarker.charset=UTF-8
spring.freemarker.content-type=text/html
spring.freemarker.expose-request-attributes=false
spring.freemarker.expose-session-attributes=false
spring.freemarker.expose-spring-macro-helpers=false
#spring.freemarker.prefix=
#spring.freemarker.request-context-attribute=
#spring.freemarker.settings.*=
#spring.freemarker.suffix=.ftl
#spring.freemarker.template-loader-path=classpath:/templates/#comma-separatedlist
#springfreemarkerview-names= #whitelistofviewnamesthatcanberesolved
freemarker和theamleaf是可以共存的
SpringBoot启动加载数据
启动加载数据CommandLineRunner
@Component
public class MyStartupRunner1 implements CommandLineRunner {
@Override
publicvoid run(String... args) throws Exception {
System.out.println(">>>>>>>>>>>>>>>服务启动执行,执行加载数据等操作<<<<<<<<<<<<<");
}
}