Idea 配置阿里云初始化创建 springboot 项目 创建项目 - Spring Initializr - Server URL 设置,修改为 https://start.aliyun.com/
SpringBoot瘦身(lib和程序分离) http://doc.jeecg.com/2043890
druid 数据库密码加密 http://doc.jeecg.com/2043967
跨域 http://www.spring4all.com/article/177
前端 JSONP
反向代理
CORS 「跨域资源共享」
浏览器支持 CORS
服务端增加一个特殊的 Header [Access-Control-Allow-Origin]
下面介绍 4 种方法:
1. 返回新的CorsFilter(全局跨域) 在任意配置类中返回一个新的CorsFilter Bean,并添加映射路径和具体的CORS配置信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 package com.bjtcrj.files.config;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.web.cors.CorsConfiguration;import org.springframework.web.cors.UrlBasedCorsConfigurationSource;import org.springframework.web.filter.CorsFilter;@Configuration public class GlobalCorsConfig { @Bean public CorsFilter corsFilter () { CorsConfiguration config = new CorsConfiguration (); config.addAllowedOrigin("*" ); config.setAllowCredentials(true ); config.addAllowedMethod("*" ); config.addAllowedHeader("*" ); config.addExposedHeader("*" ); UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource (); configSource.registerCorsConfiguration("/**" , config); return new CorsFilter (configSource); } }
在任意配置类中返回一个新的WebMvcConfigurer Bean,并重写其提供的跨域请求处理的接口,目的是添加映射路径和具体的CORS配置信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 package com.bjtcrj.files.config;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.web.servlet.config.annotation.CorsRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration public class GlobalCorsConfig { @Bean public WebMvcConfigurer corsConfigurer () { return new WebMvcConfigurer () { @Override public void addCorsMappings (CorsRegistry registry) { registry.addMapping("/**" ) .allowedOrigins("*" ) .allowCredentials(true ) .allowedMethods("GET" ,"POST" , "PUT" , "DELETE" ) .allowedHeaders("*" ) .exposedHeaders("Header1" , "Header2" ); } }; } }
3. 使用注解(局部跨域) 在方法上(@RequestMapping )使用注解 @CrossOrigin :
1 2 3 4 5 6 @RequestMapping("/hello") @ResponseBody @CrossOrigin("http://localhost:8080") public String index ( ) { return "Hello World" ; }
或者在控制器(@Controller )上使用注解 @CrossOrigin :
1 2 3 4 5 6 7 8 9 @Controller @CrossOrigin(origins = "http://xx-domain.com", maxAge = 3600) public class AccountController { @RequestMapping("/hello") @ResponseBody public String index ( ) { return "Hello World" ; } }
4. 手工设置响应头(局部跨域 ) 使用HttpServletResponse对象添加响应头(Access-Control-Allow-Origin)来授权原始域,这里Origin的值也可以设置为”*” ,表示全部放行
1 2 3 4 5 6 @RequestMapping("/hello") @ResponseBody public String index (HttpServletResponse response) { response.addHeader("Access-Control-Allow-Origin" , "http://localhost:8080" ); return "Hello World" ; }
RequestMapping DeleteMapping 1 2 3 4 @DeleteMapping public R delete(@RequestParam("idList") List<Long> idList) { xxxx }
请求示例:
1 2 DELETE /cmsTContent?idList=1,2,3 HTTP/1.1 Host: http://localhost:8088/museum
配置 Tomcat 默认 Tomcat 的最大线程数是 200,最大连接数是 10000
1 2 3 4 5 6 7 8 9 10 11 12 13 server: tomcat: min-spare-threads: 10 max-threads: 500 connection-timeout: 180000 max-connections: 10000 max-http-form-post-size: 0 uri-encoding: UTF-8
配置内存
-Xms : 设置 Java 堆栈的初始化大小
-Xmx : 设置最大的 java 堆大小
1 java -server -Xms512m -Xmx4096m -jar springboot-1.0 .jar
设置文件编码 UTF-8 1 java -server -Xms512m -Xmx4096m -Dfile.encoding=utf-8 -jar fast-module-basic-mock-start.jar
配置OracleDriver
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 spring : datasource : username : scm password : scm url : jdbc:oracle:thin:@127.0.0.1:1521:orcl driver-class-name : oracle.jdbc.OracleDriver type : com.zaxxer.hikari.HikariDataSource hikari : auto-commit : true connection-test-query : SELECT 1 FROM DUAL connection-timeout : 30000 idle-timeout : 30000 max-lifetime : 1800000 maximum-pool-size : 15 minimum-idle : 5 pool-name : DatebookHikariCP spring : datasource : druid : driver-class-name : oracle.jdbc.OracleDriver username : cmsczce password : cmsczce url : jdbc:oracle:thin:@127.0.0.1:1521:orcl initial-size : 5 min-idle : 5 maxActive : 20 maxWait : 60000 timeBetweenEvictionRunsMillis : 60000 minEvictableIdleTimeMillis : 300000 validationQuery : SELECT 1 FROM DUAL testWhileIdle : true testOnBorrow : false testOnReturn : false poolPreparedStatements : true maxPoolPreparedStatementPerConnectionSize : 20 aop-patterns : org.jeecg.modules.*.mapper.*,org.jeecg.modules.*.service.* filters : stat,wall,slf4j connectionProperties : druid.stat.mergeSql\=true;druid.stat.slowSqlMillis\=5000 stat-view-servlet : enabled : true loginUsername : admin loginPassword : 123456 allow : web-stat-filter : enabled : true
配置 MySQLDriver
1 2 3 4 5 6 7 8 9 10 spring.datasource.username =root spring.datasource.password =root spring.datasource.driver-class-name =com.mysql.jdbc.Driver spring.datasource.url =jdbc:mysql://127.0.0.1:3306/datebook?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false&zeroDateTimeBehavior=convertToNull spring.datasource.driver-class-name =com.mysql.cj.jdbc.Driver spring.datasource.url =jdbc:mysql://127.0.0.1:3306/spring-boot-jdbc?charset=utf8mb4&useSSL=false&allowPublicKeyRetrieval=true
配置 H2 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 spring: datasource: driver-class-name: org.h2.Driver url: jdbc:h2:file:./emdata/camera username: sa password: 123456 h2: console: path: /h2-console enabled: true settings: web-allow-others: true jpa: hibernate: ddl-auto: update
扫描 mapper 接口 在启动类加上注解
1 @MapperScan("com.example.demo.demo.mapper")
扫描 mybatis mapper xml 文件 application.properties
1 mybatis.mapper-locations =classpath*:/mappers/*.xml
修改端口为 8088
,application.properties
文件
get 请求头参数大小 Tomcat和Jetty的实际默认值为8kB,Undertow的默认值为1MB。 要修改最大 HTTP header大小,在application.yml文件中进行如下配置:
1 2 server: max-http-header-size: 20MB
1 2 3 4 5 6 server: tomcat: max-swallow-size: -1 max-http-post-size: -1
1 2 spring.servlet.multipart.max-file-size =100MB spring.servlet.multipart.max-request-size =100MB
中文乱码 1 2 3 4 5 server.tomcat.uri-encoding =UTF-8 spring.http.encoding.force =true spring.http.encoding.enabled =true spring.http.encoding.charset =UTF-8 spring.messages.encoding =UTF-8
自定义配置 1 2 3 4 5 params.db =mydb spring.datasource.url =jdbc:mysql://jeecg-boot-mysql:3306/${params.db}?characterEncoding=UTF-8&useUnicode=true&useSSL=false&tinyInt1isBit=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
编译、打包插件-build:plugin 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 <build > <plugins > <plugin > <groupId > org.apache.maven.plugins</groupId > <artifactId > maven-compiler-plugin</artifactId > <version > 3.8.1</version > <configuration > <source > 1.8</source > <target > 1.8</target > <encoding > UTF-8</encoding > </configuration > </plugin > <plugin > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-maven-plugin</artifactId > <version > 2.3.7.RELEASE</version > <configuration > <mainClass > com.example.pdfjava.PdfjavaApplication</mainClass > </configuration > <executions > <execution > <id > repackage</id > <goals > <goal > repackage</goal > </goals > </execution > </executions > </plugin > </plugins > </build >
打包时指定 profile 类型
打包时排除指定目录 1 2 3 4 5 6 7 8 9 10 11 12 13 14 <build > <resources > <resource > <directory > src/main/resources</directory > <filtering > true</filtering > <excludes > <exclude > static/**</exclude > <exclude > jeecg/**</exclude > </excludes > </resource > </resources > </build >
静态资源
获取静态资源绝对路径 1 2 ResourceUtils.getURL("classpath:static" ).getPath(); ResourceUtils.getURL("classpath:resources" ).getPath();
启动参数 启动类 1 2 3 4 5 6 System.setProperty("nacos.standalone" , standalone); System.setProperty("nacos.core.auth.enabled" , enabled); System.setProperty("server.tomcat.basedir" ,"logs" ); System.setProperty("server.port" ,"8848" ); SpringApplication.run(JeecgNacosApplication.class, args);
启动配置参数 1 2 3 4 5 6 7 //修改端口为 9000 //java 程序启动参数:优先级最高 java -jar files-0.0.1-SNAPSHOT.jar --server.port=9000 //JVM 参数第二 java -Dserver.port=9000 -jar files-0.0.1-SNAPSHOT.jar //优先级最低 //配置文件:server.port=9000
启动时指定外部配置文件 注意:启动 jar 时,默认会从当前目录找 application.yml 或 application-xxx.yml 配置文件
1 2 # 使用外部配置文件 java -jar exam-full-api.jar -Dspring.config.location=D:/ls/application.yml
启动时指定 profile 文件 1 2 3 4 5 # application-dev.yml java -jar xxx.jar --spring.profiles.active=dev java -jar --spring.profiles.active=test app.jar --server.port=8081 java -jar -Dspring.profiles.active=test app.jar --server.port=8081
启动时指定 MySQL 数据库地址
读取 application.yml 自定义配置信息 1 2 3 4 5 6 7 8 9 10 11 12 13 params: name: portal event: departZhifaduiOrgcode: 610204123 extend-fields: eventFlag: true zfEventDocTableValueQuote: true zfEventDocConstantValueQuote: true
方式一:通过 ConfigurationProperties 示例1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 package org.jeecg.modules.event.config;import org.springframework.boot.context.properties.ConfigurationProperties;import org.springframework.stereotype.Component;@Data @Component("eventConfig") @ConfigurationProperties(prefix = "event") public class EventConfig { private String departZhifaduiOrgcode = "默认值" ; private Map<String, Boolean> extendFields; private boolean zfEventDocTableValueQuote = false ; private boolean zfEventDocConstantValueQuote = false ; }
使用
1 2 @Resource private EventConfig eventConfig;
示例2 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 @Data @Component @ConfigurationProperties(prefix = "wx.mp") public class WxMpProperties { private boolean useRedis; private RedisConfig redisConfig; @Data public static class RedisConfig { private String host; private Integer port; private String password; } private List<MpConfig> configs; @Data public static class MpConfig { private String appId; private String secret; private String token; private String aesKey; } @Override public String toString () { return JsonUtils.toJson(this ); } }
1 2 3 4 5 6 7 8 9 10 11 12 wx: mp: useRedis: false redisConfig: host: tcboot-redis port: 6379 configs: - appId: xxx secret: xxx token: zyxx aesKey: xxx
1 2 @Resource private WxMpProperties wxMpProperties;
方式二:通过 @Value 注解
spring bean 定义,成员变量通过 @Value 获取
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 @Component @PropertySource(value = "classpath:test.yml") public class YamlProperties { @Value("${params.name}") private String name; @Value("${params.name:}") private String name; @Value("${some.key:hello}") private String stringWithDefaultValue; @Value("${some.key:true}") private Boolean booleanWithDefaultValue; @Value("${some.key:42}") private Integer intWithDefaultValue; @Value("${some.key:one,two,three}") private String[] stringArrayWithDefaults; @Value("${some.key:1,2,3}") private int [] intArrayWithDefaults; }
方式三:通过 applicationContext 获取 1 2 3 4 5 6 7 8 9 10 11 12 13 @Resource ApplicationContext applicationContext; @NotNull private String getAppCode () { return applicationContext.getEnvironment().getProperty("params.name" ); } ConfigurableApplicationContext application = SpringApplication.run(JeecgSystemApplication.class, args);Environment env = application.getEnvironment();String ip = InetAddress.getLocalHost().getHostAddress();String port = env.getProperty("server.port" );String path = oConvertUtils.getString(env.getProperty("server.servlet.context-path" ));
常用Bean 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 @Autowired private RequestMappingHandlerMapping requestMappingHandlerMapping; Map<RequestMappingInfo, HandlerMethod> handlerMethods = requestMappingHandlerMapping.getHandlerMethods(); for (Map.Entry<RequestMappingInfo, HandlerMethod> handlerMethodEntry : handlerMethods.entrySet()) { RequestMappingInfo requestMappingInfo = handlerMethodEntry.getKey(); Set<String> patterns = requestMappingInfo.getPatternsCondition().getPatterns(); String path = patterns.iterator().next(); Open open = handlerMethodEntry.getValue().getMethodAnnotation(Open.class); } @Autowired private Environment environment; String serviceId = environment.getProperty("spring.application.name" );
SpringBoot修改内置tomcat版本 https://blog.csdn.net/HcJsJqJSSM/article/details/116401670
容器 Tomcat 替换为 Undertow Spring Boot内嵌容器默认为Tomcat
移除 tomcat 依赖
1 2 3 4 5 6 7 8 9 10 <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-web</artifactId > <exclusions > <exclusion > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-tomcat</artifactId > </exclusion > </exclusions > </dependency >
添加 Undertow 依赖
1 2 3 4 <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-undertow</artifactId > </dependency >
配置
1 2 3 4 5 6 7 8 9 10 server: port: 8084 http2: enabled: true undertow: io-threads: 16 worker-threads: 256 buffer-size: 1024 buffers-per-region: 1024 direct-buffers: true
注解 @DependsOn - Bean 执行顺序 1 2 3 4 5 @Bean @DependsOn("eventConfig") public SqlSessionFactory sqlSessionFactory (DataSource dataSource) throws Exception {}
应用启停管理 windows 启动 1 2 3 4 5 6 7 8 9 10 11 12 13 java -server -Xms1g -Xmx2g -jar xxxxx-0.0.1-SNAPSHOT.jar -Dloader.path=C:\libs -Dfile.encoding=utf-8 start cmd /c "title emergency && java -jar -Dfile.encoding=utf-8 C:\tongchuan\svn\emergency\jeecg-module-emergency-start\target\jeecg-module-emergency-start.jar"
停止 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 taskkill /f /im java.exe @echo off setlocal enabledelayedexpansion set port=7010for /f "tokens=1-5" %%a in ('netstat -ano ^| find ":%port%"' ) do ( if "%%e%" == "" ( set pid=%%d ) else ( set pid=%%e ) echo !pid! taskkill /f /pid !pid! ) for %%a in (8848,7011) do ( set pid=0 for /f "tokens=2,5" %%b in ('netstat -ano ^| findstr ":%%a"' ) do ( set temp=%%b for /f "usebackq delims=: tokens=1,2" %%i in (`set temp`) do ( if %%j==%%a ( taskkill /f /pid %%c set pid=%%c echo 端口号【%%a】相关进程以杀死 ) else ( echo 不是本机占用端口【%%a】 ) ) ) if !pid!==0 ( echo 端口号【%%a】没有占用 ) ) kill -9 `lsof -t -i:7010`
Linux 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 APP_NAME=app.jar usage() { echo "Usage: sh 执行脚本.sh [start|stop|restart|status]" exit 1 } is_exist() { pid=$(ps -ef | grep $APP_NAME | grep -v grep | awk '{print $2}') if [ -z "$pid" ]; then return 1 else return 0 fi } start() { is_exist if [ $? -eq "0" ]; then echo "$APP_NAME is already running. pid=$pid ." else nohup java -jar $APP_NAME >/dev/null 2>&1 & fi } stop() { is_exist if [ $? -eq "0" ]; then kill -9 $pid else echo "$APP_NAME is not running" fi } status() { is_exist if [ $? -eq "0" ]; then echo "$APP_NAME is running. Pid is $pid" else echo "$APP_NAME is NOT running." fi } restart() { stop start } case "$1" in "start") start ;; "stop") stop ;; "status") status ;; "restart") restart ;; *) usage ;; esac
Windows 服务形式运行
目标:实现服务随系统自启动
下载Windows Service Wrapper 工具
文件重命名为 xxxxx-service.exe
同目录下新建同名 xxxxx-service.xml
文件
1 2 3 4 5 6 7 8 9 10 <service > <id > xxxxx</id > <name > xxxxx</name > <description > xxxxx</description > <logpath > C:\xxxxx</logpath > <logmode > roll</logmode > <depend > </depend > <executable > C:\xxxxx\start.bat</executable > <stopexecutable > C:\xxxxx\stop.bat</stopexecutable > </service >
使用
安装
1 xxxxx-service.exe install
卸载
1 xxxxx-service.exe uninstall
启动
停止
日志注解 @Slf4j(基于 lombok) SpringBoot 默认集成了 logback + slf4j
,所以只需添加 lombok
即可
pom.xml 1 2 3 4 5 <dependency > <groupId > org.projectlombok</groupId > <artifactId > lombok</artifactId > <optional > true</optional > </dependency >
application.yml 1 2 3 4 5 6 7 8 logging: level: com.bjtcrj.files: debug com.baomidou.mybatisplus: DEBUG file: path: ./log name: files.log max-history: 100
使用 1 2 3 @Slf4j log.info("xxx" );
JVM 工具远程连接
启动
1 java -server -Xms512m -Xmx768m -jar -Djava.rmi.server.hostname=192.168.0.110 -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9000 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false files-0.0.1-SNAPSHOT.jar
连接
文件上传 方案一 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @PostMapping(value = "/addBatch/{type}") public R addBatch (@PathVariable("type") String type, @RequestParam("file") MultipartFile file) { Iterable<Law> iterable = lawService.getAll(); Set<String> result = StreamSupport.stream(iterable.spliterator(), false ).map(Law::getLawtype).collect(Collectors.toSet()); if (result.contains(type)) { return R.fail(ResultCode.ERROR, "type 字段已存在" ); } return R.success(lawService.add(file, type)); }
方案二 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 @PostMapping("/uploadFiles") @ResponseBody public ResponseBean upload (FilesuploadReq entity, HttpServletRequest request) { ResponseBean resultRes = new ResponseBean (); int code = ResponseBean.CODE_SUCCESS; String msg = "上传成功" ; String project = entity.getProject(); String module = entity.getModule(); MultipartResolver resolver = new StandardServletMultipartResolver (); MultipartHttpServletRequest mRequest = resolver.resolveMultipart(request); Map<String, MultipartFile> fileMap = mRequest.getFileMap(); List<String> imgs = new ArrayList <>(); Collection<MultipartFile> files = fileMap.values(); for (MultipartFile file : files) { String fileName = file.getOriginalFilename(); String tempFilePath = FileGenerator.getFilePath(project, module , fileName); String filepathname = FileGenerator.ROOTPATH + tempFilePath; File dest = new File (filepathname); try { file.transferTo(dest); String dateStr = FileGenerator.getDateStringYMDHMS(new Date ()); PicDealTools.createWaterMarkByText(filepathname, dateStr, filepathname,0 ); imgs.add(tempFilePath); } catch (IOException e) { code = ResponseBean.CODE_FAILED; msg = "上传失败:" +e.getMessage(); dest.deleteOnExit(); e.printStackTrace(); } finally { resultRes.setCode(code); resultRes.setMsg(msg); String join = StringUtils.join(imgs, '|' ); resultRes.setData(join); } } return resultRes; }
工具类 RequestContextHolder - 获取 request 1 HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
获取所有接口信息:类名、方法名、接口路径、请求Method 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 RequestMappingHandlerMapping mapping = applicationContext.getBean(RequestMappingHandlerMapping.class);Map<RequestMappingInfo, HandlerMethod> map = mapping.getHandlerMethods(); List<Map<String, String>> list = new ArrayList <>(); for (Map.Entry<RequestMappingInfo, HandlerMethod> m : map.entrySet()) { Map<String, String> map1 = new HashMap <>(); RequestMappingInfo info = m.getKey(); HandlerMethod method = m.getValue(); PatternsRequestCondition p = info.getPatternsCondition(); for (String url : p.getPatterns()) { map1.put("url" , url); } map1.put("className" , method.getMethod().getDeclaringClass().getName()); map1.put("method" , method.getMethod().getName()); RequestMethodsRequestCondition methodsCondition = info.getMethodsCondition(); for (RequestMethod requestMethod : methodsCondition.getMethods()) { map1.put("type" , requestMethod.toString()); } System.out.println(String.format("%s\t%s\t%s\t%s" , map1.get("url" ), map1.get("className" ), map1.get("method" ), map1.get("type" ))); }
问题 HTTP method names must be tokens 解决:检查请求协议类型是否为 https
,也许应该是 http
The request is larger than the server is willing or able to process 1 2 3 spring: codec: max-in-memory-size: 2MB