springboot启动
正常启动
@SpringBootApplication
public class Application {
public static void main (String [] args ) {
SpringApplication .run (Application .class , args);
}
}
启动时输出pid文件
@SpringBootApplication
public class Application {
public static void main (String [] args ) {
SpringApplication application = new SpringApplication (Application .class );
application.addListeners (new ApplicationPidFileWriter ());
ConfigurableApplicationContext applicationContext = application.run (args);
applicationContext.registerShutdownHook ();
}
}
指定项目访问名称
项目访问路径
server.servlet.context-path = itemAccessName
springboot启动指定参数
启动时指定日志路径:
-Domp.logging.path =logs
${sys:omp.logging.path :-./log /}
添加指定系统参数
System.setProperty("" , "" );
springboot配置文件
spring.pid.file =application.pid 默认pid文件名称
spring.application.name =itemName 启动项目名称
eureka.instance.prefer-ip-address = true
eureka.instance.preferIpAddress = true
eureka.instance.instance-id = ${spring.cloud.client.ip-address} :${server.port}
logging.config = config/logback-spring.xml
springboot加载资源文件
InputStream inputStream = this .getClass().getClassLoader().getResourceAsStream("a.txt" );
IOUtils.toString(inputStream);
springboot配置文件加载顺序
application.properties 配置文件加载顺序
file:./config/
file:./
classpath:/config/
classpath:/
加载优先级由高到低,高优先级的配置会覆盖低优先级的配置
sprinboot测试用例
@Slf4j
@RunWith (SpringRunner.class)
@SpringBootTest (classes = Application.class)
@Transactional
@AutoConfigureMockMvc
出现下面错误时查询是否是导入的org.junit.Test
org.junit.runners.model.InvalidTestClassError : Invalid test class
AOP
@EnableAspectJAutoProxy
@Aspect @Pointcut @Before @After @Around @AfterThrowing @AfterReturning
@EnableTransactionManagement
InfrastructureAdvisorAutoProxyCreator
@EnableAspectJAutoProxy
AnnotationAwareAspectJAutoProxyCreator
CglibAopProxy DynamicAdvisedInterceptor intercept
ReflectiveMethodInvocation.proceed()
ExposeInvocationInterceptor.invoke()
异常返回通知
AspectJAfterThrowingAdvice.invoke()
正常返回通知
AfterReturningAdviceInterceptor.invoke()
后置通知
AspectJAfterAdvice.invoke()
环绕通知
AspectJAroundAdvice.invoke()
前置通知
MethodBeforeAdviceInterceptor.invoke()
正常过程
@Arount :执行目标方法之前
@Before----- 除法运行之前
----div----
@Arount :执行目标方法之后
@After----- 除法结束
@AfterReturning----- 除法正常返回
异常过程
@Arount :执行目标方法之前
@Before----- 除法运行之前
----div----
@After----- 除法结束
@AfterThrowing----- 运行异常
execution(* * cn.com.spring.service.impl..*.*(..))
1 )* 所有的修饰符(如public)
2 )* 所有的返回类型(如void)
3 ).. 所有的包及其子包下的文件
4 )* 所有的类名
5 )* 所有的方法名
6 )* ..所有的参数名
配置文件参数自动转List类型
参数自动转为List
@Value("#{'${csp.security:menuList,portalList} '.split(',')}" )
private List<String> verifyTokenUrlList;
maven jar包
<parent >
<groupId > org.springframework.boot</groupId >
<artifactId > spring-boot-starter-parent</artifactId >
<version > 2.7.13</version >
</parent >
<dependency >
<groupId > org.springframework.boot</groupId >
<artifactId > spring-boot-starter-web</artifactId >
</dependency >
<dependency >
<groupId > org.springframework.boot</groupId >
<artifactId > spring-boot-starter-test</artifactId >
<scope > test</scope >
</dependency >
打包插件
org.springframework.boot mvn打包springboot项目jar或war
spring-boot-maven-plugin
org.apache.maven.plugins 测试用例插件(默认已有)
maven-surefire-plugin
org.apache.maven.plugins 资源插件(处理资源文件)
maven-resources-plugin
org.apache.maven.plugins 部署插件(发布远程仓库)
maven-deploy-plugin
org.apache.maven.plugins jar包插件(打成可运行jar包)
maven-jar-plugin
org.apache.maven.plugins 依赖插件(添加额外jar包)
maven-dependency-plugin
pl.project13.maven git插件(获取git版本信息)
git-commit-id-plugin
maven-assembly-plugin 装配插件(支持定制化打包)
@InitBinder日期格式化
@InitBinder
protected void initBinder (WebDataBinder binder ) {
binder.registerCustomEditor (Date .class , new PropertyEditorSupport () {
@Override
public void setAsText (String text) throws IllegalArgumentException {
Date date = null ;
try {
date = new SimpleDateFormat ("yyyy-MM-ddHH:mm:ss" ).parse (text);
} catch (ParseException e) {
}
if (date == null ) {
try {
date = new SimpleDateFormat ("yyyy-MM-dd" ).parse (text);
} catch (ParseException e1) {
}
}
setValue (date);
}
});
}
前后端交互日期格式化
前台传后台时间格式化(form表单形式)
@DateTimeFormat (pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat (pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date date ;
前台传后台时间格式化(json形式)
@JsonFormat (pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
后台传前台时间格式化
@JsonFormat (pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
手动控制事务
DefaultTransactionDefinition def = new DefaultTransactionDefinition ();
def .setPropagationBehavior(TransactionDefinition .PROPAGATION_REQUIRES_NEW );
TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(def ) ;
try {
dataSourceTransactionManager.commit(transactionStatus);
} catch (Exception e) {
log.error("" , e);
dataSourceTransactionManager.rollback(transactionStatus);
throw new RuntimeException (e);
}
Validation参数验证使用时调用
Validation.buildDefaultValidatorFactory ().getValidator ().validate (obj).forEach ((s)->{
throw new RuntimeException ("["+s.getPropertyPath()+s.getMessage ()+"]");
});
newDecimalFormat ("#,###" ) .format (123456789 ) ) -> 123 ,456 ,789
Springboot项目无法加载配置文件时添加插件
<plugin >
<groupId > org.apache.maven.plugins</groupId >
<artifactId > maven-jar-plugin</artifactId >
<configuration >
<excludes >
<exclude > logback-spring.xml</exclude >
<exclude > application.properties</exclude >
</excludes >
</configuration >
</plugin >
修复跨站脚本漏洞
org.springframework.web.util.HtmlUtils.htmlEscape(str );
spring boot关闭actuator路径
关闭actuator所有端点
management.endpoints.enabled-by-default =false
禁用监控HTTP端点,因为http端口的范围是:1 ~65535 ,因此-1 是访问不了的,此时访问/actuator路径也是404 了
management.server.port = -1
actuator默认开启了health、info端点,可以单独关闭
management.endpoint.info.enabled=false
management.endpoint.health.enabled=false
单独开启服务端点,如开启info、health
management.endpoint.info.enabled=true
management.endpoint.health.enabled=true
批量暴露端点,例如暴露mapping、metrics端点
management.endpoints.web.exposure.include =mapping,metric
暴露所有端点
management.endpoints.web.exposure.include =*
日志
<dependency >
<groupId > org.projectlombok</groupId >
<artifactId > lombok</artifactId >
<version > 1.18.20</version >
</dependency >
@Slf4j
或者Logger log = LoggerFactory.getLogger(A.class);
异常统一处理
@ControllerAdvice
@ExceptionHandler ({Exception.class})
@ResponseBody
public void methodException(HttpServletRequest request, Exception ex, HttpServletResponse response) throws IOException {
response .setStatus (HttpStatus.SC_NOT_ACCEPTABLE);
response .setContentType ("application/json;charset=UTF-8" );
response .getWriter ().write (JSON.toJSONString(new JSONObject().fluentPut("code" , "111" ).fluentPut("msg" , ex.getMessage())));
}
url匹配判断
PathMatcher antPathMatcher = new AntPathMatcher ();
antPathMatcher.match("/url/**" , req.getServletPath());
url请求强匹配
@Configuration
public class WebConfig extends WebMvcConfigurationSupport {
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.setUseSuffixPatternMatch(false ).setUseTrailingSlashMatch(true );
}
}
post请求时,验证传递的参数名是否必须在实体类中存在
@Configuration
public class WebConfig extends WebMvcConfigurationSupport {
@Override
public void configureMessageConverters(List <HttpMessageConverter <?>> converters) {
ObjectMapper objectMapper = Jackson2ObjectMapperBuilder .json().build();
objectMapper.configure(DeserializationFeature .FAIL_ON_UNKNOWN_PROPERTIES , false );
converters.add(new MappingJackson2HttpMessageConverter (objectMapper));
}
}
自动时间转换
在实体类的Date类型字段上添加此注解,在入参、及转成json格式时会转成字符串
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss" )
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8
Valid参数验证实例
@Valid 支持嵌套,可以验证类中类属性
@Validated 不支持嵌套,仅可以验证本类属性
常用的用法
@NotNull
@NotEmpty
@Pattern (regexp = "^[0-9]?$" )
嵌套实例
@Data
public class A{
@Valid
@NotEmpty
@NotNull
private List<B> list;
@Data
public static class B{
@NotNull
private Long objectId;
}
}
获取request、respone
HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
HttpServletResponse response = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getResponse();
http响应返回状态码
响应分为五类:信息响应(100 –199 ),成功响应(200 –299 ),重定向(300 –399 ),客户端错误(400 –499 )和服务器错误 (500 –599 ):
日志可以使用这种方式替换变量
log .info ("消息内容替换[{}]" , "message" );
输出为:消息内容替换[message]
过滤器、拦截器
@Component
public class MyInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return super .preHandle(request, response, handler);
}
}
@Configuration
public class MyConfig extends WebMvcConfigurationSupport {
@Autowired
private MyInterceptor myInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(myInterceptor).addPathPatterns("/**" ).excludePathPatterns("/error/**" );
}
}
@WebFilter (filterName = "MyFilter" , urlPatterns = "/*" )
public class MyFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException , ServletException {
chain.doFilter(req, resp);
}
}
添加过滤器判断系统仅支持post请求
@WebFilter(filterName = "MyFilter", urlPatterns = "/*")
public class MyFilter implements Filter {
private final static PathMatcher antPathMatcher = new AntPathMatcher ();
@Override
public void doFilter (ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
if (!antPathMatcher.match("/info/**" , request.getServletPath())) {
if ("GET" .equals(request.getMethod())) {
req.getRequestDispatcher("/error/handleError" ).forward(req, resp);
return ;
}
}
chain.doFilter(req, resp);
}
}
@RestController
@RequestMapping(value = "/api/error")
public class ErrorController {
@GetMapping("handleError")
public void handleError () {
throw new ServiceException ("Request method 'GET' not supported" );
}
}
获取处理项目的URL
UrlPathHelper helper = new UrlPathHelper ();
String uri = helper.getOriginatingServletPath (request);
for (Map .Entry <RequestMappingInfo , HandlerMethod > entry : requestMappingHandlerMapping.getHandlerMethods ().entrySet ()) {
for (String url : entry.getKey ().getPatternsCondition ().getPatterns ()) {
System .out .println (url);
}
}
HttpServletRequest request = ((ServletRequestAttributes ) RequestContextHolder .getRequestAttributes ()).getRequest ();
for (Map .Entry <RequestMappingInfo , HandlerMethod > entry : RequestMappingHandlerMapping .getHandlerMethods ().entrySet ()) {
RequestMappingInfo m = entry.getKey ().getMatchingCondition (request);
Set <String > urlPatterns = m.getPatternsCondition ().getPatterns ();
HandlerMethod value = entry.getValue ();
}
spring自带缓存功能
@CacheEvict (allEntries=true)
@Cacheable (value="a" , key="#id" )
https :
feign的调用
Object obj = Feign.builder().client(applicatonContext.gerBean(Client.class ))
.encoder(applicatonContext.gerBean(Encoder.class ))
.decoder(applicatonContext.gerBean(Decoder.class ))
.contract(new SpringMvcContract())
.target(Object .class , "http://microServiceName/path" );
springcloud高版本ribbon问题
springcloud高版本不能使用ribbon,可以直接删除ribbon,直接使用loadbalancer
https://blog.csdn.net/SirLZF/article/details/117127361
解决类上@FeignClient、@RequestMapping同时存在时的报错问题
@Bean
@Primary
public SpringMvcContract feignContract (List<AnnotatedParameterProcessor> parameterProcessors,
ConversionService feignConversionService,
FeignClientProperties feignClientProperties ) {
boolean decodeSlash = feignClientProperties == null || feignClientProperties.isDecodeSlash ();
return new SpringMvcContract (parameterProcessors, feignConversionService, decodeSlash) {
@Override
protected void processAnnotationOnClass (MethodMetadata data, Class<?> clz ) {
CollectionFormat collectionFormat = findMergedAnnotation (clz, CollectionFormat .class );
if (collectionFormat != null ) {
data.template ().collectionFormat (collectionFormat.value ());
}
}
};
}
测试用例注解
@Transactional
@Rollback (true)
@RunWith (SpringRunner.class)
@SpringBootTest (classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
配置druid的sql监控生效的配置
spring.datasource.druid.web-stat-filter.enabled = true
spring.datasource.druid.stat-view-servlet.enabled = true
spring.datasource.druid.stat-view-servlet.allow = 127.0 .0.1 /0
spring.datasource.druid.filter.stat.enabled = true
spring.datasource.druid.filter.stat.log-slow-sql = true
spring.datasource.druid.filter.stat.merge-sql = true
spring.datasource.druid.filter.stat.slow-sql-millis = 3000
spring.datasource.druid.stat-view-servlet.reset-enable = false
spring.datasource.druid.stat-view-servlet.login-username = admin
spring.datasource.druid.stat-view-servlet.login-password = admin@123
定时任务设置
@Scheduled (cron = "${refresh.space:0 0 3 * * ?}" )
初始化后执行方法
@PostConstruct
日期自动转换器
import org.springframework.core.convert.converter.Converter;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class DateConverter implements Converter <String, Date> {
private static final List<String> FORMAT_LIST = new ArrayList <>();
static {
FORMAT_LIST.add("yyyy-MM" );
FORMAT_LIST.add("yyyy-MM-dd" );
FORMAT_LIST.add("yyyy-MM-dd HH:mm" );
FORMAT_LIST.add("yyyy-MM-dd HH:mm:ss" );
}
@Override
public Date convert (String source) {
String value = source.trim();
if ("" .equals(value)) {
return null ;
}
if (value.matches("^\\d{4}-\\d{1,2}$" )) {
return parseDate(value, FORMAT_LIST.get(0 ));
} else if (value.matches("^\\d{4}-\\d{1,2}-\\d{1,2}$" )) {
return parseDate(source, FORMAT_LIST.get(1 ));
} else if (value.matches("^\\d{4}-\\d{1,2}-\\d{1,2} {1}\\d{1,2}:\\d{1,2}$" )) {
return parseDate(source, FORMAT_LIST.get(2 ));
} else if (value.matches("^\\d{4}-\\d{1,2}-\\d{1,2} {1}\\d{1,2}:\\d{1,2}:\\d{1,2}$" )) {
return parseDate(value, FORMAT_LIST.get(3 ));
} else {
throw new IllegalArgumentException ("Invalid boolean value '" + source + "'" );
}
}
private Date parseDate (String dateStr, String format) {
Date date = null ;
try {
DateFormat dateFormat = new SimpleDateFormat (format);
date = dateFormat.parse(dateStr);
} catch (Exception e) {
log.error("格式化日期异常" , e);
}
return date;
}
}
SpringBoot如何解决跨域问题
跨域可以在前端通过 JSON P 来解决,但是 JSON P 只可以发送 GET 请求,
无法发送其他类型的请求,在 RESTful 风格的应用中,就显得非常鸡肋,
因此我们推荐在后端通过 (CORS ,Cross -origin resource sharing)来解决跨域问题。
这种解决方案并非SpringBoot 特有的,在传统的SSM 框架中,就可以通过 CORS 来解决跨域问题,
只不过之前我们是在 XML 文件中配置 CORS ,
现在可以通过实现WebMvcConfigurer 接口然后重写addCorsMappings方法解决跨域问题。
@Override
public void addCorsMappings (CorsRegistry registry ) {
registry.addMapping ("/**" )
.allowedOrigins ("*" )
.allowCredentials (true )
.allowedMethods ("GET" , "POST" , "PUT" , "DELETE" , "OPTIONS" )
.maxAge (3600 );
}
请求参数加签名
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
@WebFilter(filterName = "GetParamFilter", urlPatterns = "/*", dispatcherTypes = DispatcherType.REQUEST)
public class GetParamFilter implements Filter {
private static final String SIGN_NAME = "sign" ;
@Override
public void doFilter (ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
if ("GET" .equalsIgnoreCase(request.getMethod())) {
if (!validSign(request)) {
responseJsonMessage(resp, "错误信息提示" );
return ;
}
}
chain.doFilter(req, resp);
}
public static boolean validSign (HttpServletRequest request) {
Map<String, String> paramMap = new HashMap <>();
Enumeration<String> enumeration = request.getParameterNames();
while (enumeration.hasMoreElements()) {
String paramName = enumeration.nextElement();
paramMap.put(paramName, request.getParameter(paramName));
}
paramMap.remove(SIGN_NAME);
if (MapUtils.isEmpty(paramMap) || StringUtils.isBlank(request.getParameter(SIGN_NAME))) {
return true ;
}
return StringUtils.equals(request.getParameter(SIGN_NAME), cn.hutool.crypto.SecureUtil.md5("待加密的字符串" ));
}
private void responseJsonMessage (ServletResponse resp, Object obj) throws IOException {
resp.setContentType("application/json; charset=utf-8" );
PrintWriter writer = resp.getWriter();
writer.print(JSONObject.toJSONString(obj, SerializerFeature.WriteMapNullValue, SerializerFeature.WriteDateUseDateFormat));
writer.close();
resp.flushBuffer();
}
}
适配管理库时,需要添加下面数据库适配器
# 添加下面后,在xml中可以使用_databaseId来进行各个数据库的判断了
@Configuration
public class DatabaseAdapterConfig {
@Bean
public DatabaseIdProvider getDatabaseIdProvider () {
DatabaseIdProvider databaseIdProvider = new VendorDatabaseIdProvider();
Properties p = new Properties();
p.setProperty("PostgreSQL" , "postgres" );
p.setProperty("DM DBMS" , "dm7" );
p.setProperty("Oracle" , "oracle" );
p.setProperty("MySQL" , "mysql" );
databaseIdProvider.setProperties(p);
return databaseIdProvider;
}
}
jpa低版本适配达梦
#方案一 添加兼容包加配置参数:
1 、添加兼容包:DmDialect-for -hibernate
2 、添加参数参数(涉及类JpaProperties,):spring.jpa.database-platform = org.hibernate.dialect.DmDialect
<dependency>
<groupId>com.dameng</groupId>
<artifactId>DmDialect-for -hibernate5.6 </artifactId>
<version>8.1 .3 .140 </version>
</dependency>
#重写了类JpaBaseConfiguration的方法:jpaVendorAdapter(),并注册bean
@Configuration
public class JpaVendorAdapterConfig {
@Value("${spring.jpa.database-platform:org.hibernate.dialect.DmDialect} " )
private String databasePlatform;
@Value("${dm.driver.class.name:dm.jdbc.driver.DmDriver} " )
private String dmDriverClassName;
@Value("${spring.datasource.driver-class-name} " )
private String springDatasourceDriverClassName;
@Bean
@Primary
public JpaVendorAdapter jpaVendorAdapter(JpaProperties properties) {
AbstractJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
adapter.setShowSql(properties.isShowSql());
if (properties.getDatabase() != null ) {
adapter.setDatabase(properties.getDatabase());
}
if (StringUtils.isNotBlank(properties.getDatabasePlatform())) {
adapter.setDatabasePlatform(properties.getDatabasePlatform());
} else if (StringUtils.equalsIgnoreCase(springDatasourceDriverClassName, dmDriverClassName)) {
adapter.setDatabasePlatform(databasePlatform);
}
adapter.setGenerateDdl(properties.isGenerateDdl());
return adapter;
}
}
方案二 通过url添加参数让jpa使用oracle的类
url连接添加参数:?compatibleMode=oracle&comOra=true 添加1 个参数即可(配置参数的作用位置DmdbDatabaseMetaData #getDatabaseProductName())
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
· 上周热点回顾(2.17-2.23)