首页
归档
留言
广告合作
友链
美女主播
Search
1
博瑞GE车机升级/降级
5,173 阅读
2
修改elementUI中el-table树形结构图标
4,540 阅读
3
Mac打印机设置黑白打印
4,535 阅读
4
Mac客户端添加腾讯企业邮箱方法
4,372 阅读
5
intelliJ Idea 2022.2.X破解
4,092 阅读
Java
HarmonyOS Next
Web前端
微信开发
开发辅助
App开发
数据库
随笔日记
登录
/
注册
Search
标签搜索
Spring Boot
Java
Spring Cloud
Mac
mybatis
WordPress
Nacos
Spring Cloud Alibaba
Mybatis-Plus
jQuery
Java Script
asp.net
微信小程序
Sentinel
UniApp
MySQL
asp.net core
IntelliJ IDEA
Jpa
树莓派
Laughing
累计撰写
576
篇文章
累计收到
1,425
条评论
首页
栏目
Java
HarmonyOS Next
Web前端
微信开发
开发辅助
App开发
数据库
随笔日记
页面
归档
留言
广告合作
友链
美女主播
搜索到
89
篇与
的结果
2020-09-28
Spring Boot 配合nginx完成跨域配置
在 springboot配置跨域 我们介绍了spring boot两种配置跨域的方式。实际项目中,我用的一般是通过nginx进行跨域设置。nginx跨域实现的几个目标肯定是能正常跨域访问为了方便跨域,我们一般对后台api进行封装,统一返回一个前缀作为区分我们先来实现第二个目标,统一后端返回的api地址。方法一、通过yaml配置通过配置文件设置server: servlet: context-path: /api这样,我们在前端的请求,都会自动加上'/api'前缀。但是这样的设置存在两个问题:所有的请求全部都是'/api'前缀。静态资源要求带'/api'前缀。所以,我们需要通过更优雅的方式来进行设置,也就是方法二。方法二、通过实现WebMvcConfigurer接口的configurePathMatch方法首先我们在配置文件,增加自定义的前缀#配置api前缀 request-path: api-path: /api注入配置信息/** * @author laughing * @date 2020/9/26 * @site https://www.xiangcaowuyu.net */ @Configuration @ConfigurationProperties(prefix = "request-path") @Data public class RequestPathProperties { private String apiPath; }增加自定义注解/** * @author laughing * @date 2020/9/26 * @site https://www.xiangcaowuyu.net */ @RestController @Target({ElementType.TYPE}) @Documented @RequestMapping @Retention(RetentionPolicy.RUNTIME) public @interface ApiRestController { /** * Alias for {@link RequestMapping#name}. */ @AliasFor(annotation = RequestMapping.class) String name() default ""; /** * Alias for {@link RequestMapping#value}. */ @AliasFor(annotation = RequestMapping.class) String[] value() default {}; /** * Alias for {@link RequestMapping#path}. */ @AliasFor(annotation = RequestMapping.class) String[] path() default {}; }增加实现WebMvcConfigurer的configurePathMatch方法,配置前缀/** * @author laughing * @date 2020/9/26 * @site https://www.xiangcaowuyu.net */ @Configuration public class MyWebMvcConfig implements WebMvcConfigurer { @Resource RequestPathProperties requestPathProperties; @Override public void configurePathMatch(PathMatchConfigurer configurer) { configurer.addPathPrefix(requestPathProperties.getApiPath(), c->c.isAnnotationPresent(ApiRestController.class)); } }经过如上配置,我们所有注解@ApiRestController的请求,都会增加'/api'前缀增加两个配置类,一个通过@ApiRestController注解,一个通过普通的@RestController注解,分别访问测试/** * @author laughing * @date 2020/9/26 * @site https://www.xiangcaowuyu.net */ @ApiRestController public class NginxCorsController { @RequestMapping("/nginxCors") public String nginxCors(){ return "nginxCors"; } }/** * @author laughing * @date 2020/9/26 * @site https://www.xiangcaowuyu.net */ @RestController public class NormalController { @RequestMapping("/normal") public String normal(){ return "normal"; } }支持,完成了spring boot后台统一api地址的目标nginx配置跨域前端代码我们先配置前端页面,发起一个简单的post请求<!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script> </head> <body> <div id="myDiv"></div> <script> $(document).ready(function () { $.ajax({ url: "/api/nginxCors", type:"post", async: false, success:function(data){ $("#myDiv").html(data); } }); }); </script> </body> </html>nginx配置我们要配置的规则很简单,所有/api开头的请求,全部重定向到后端spring boot上。打开nginx配置文件,我这里使用的是默认的,及'nginx.conf'修改locationserver { listen 1234; server_name localhost; #charset koi8-r; #access_log logs/host.access.log main; #简单配置跨域 location /api { proxy_pass http://localhost:8080/api/; } location / { root html; index index.html index.htm; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } # proxy the PHP scripts to Apache listening on 127.0.0.1:80 # #location ~ \.php$ { # proxy_pass http://127.0.0.1; #} # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 # #location ~ \.php$ { # root html; # fastcgi_pass 127.0.0.1:9000; # fastcgi_index index.php; # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; # include fastcgi_params; #} # deny access to .htaccess files, if Apache's document root # concurs with nginx's one # #location ~ /\.ht { # deny all; #} }重新加载nginx配置文件这里用的win,linux需要对应替换命令nginx.exe -s reload打开页面测试,可以看到能够正常跨域
2020年09月28日
1,726 阅读
0 评论
0 点赞
2020-09-27
SpringBoot 之 @ControllerAdvice使用场景
SpringBoot 之 @ControllerAdvice使用场景@ControllerAdvice是spring 3.2版本增加的一个注解,@ControllerAdvice注解的类,可以应用到所有的@RequestMapping请求中,主要有三个应用场景:@ExceptionHandler 全局异常处理@InitBinder 全局数据预处理@ModelAttribute 全局数据绑定注意如果这三个注解直接在@Controller类中使用,则只对当前控制器生效如果@ControllerAdvice中不需要返回view,也可以使用@RestControllerAdvice,即@RestControllerAdvice = @ControllerAdvice + @ResponseBody@ExceptionHandler 全局异常处理定义全局异常处理类/** * 全局异常处理 * @author laughing * @date 2020/9/26 * @site https://www.xiangcaowuyu.net */ @RestControllerAdvice public class GlobalExceptionHandler { /** * 处理越界异常 * @param indexOutOfBoundsException 越界异常 * @return Map */ @ExceptionHandler(IndexOutOfBoundsException.class) public Map<String,Object> indexOutOfBoundsException(IndexOutOfBoundsException indexOutOfBoundsException){ Map<String,Object> map = new HashMap<>(2); map.put("code",400); map.put("msg","越界异常"); return map; } /** * 处理空引用异常 * @param nullPointerException 空引用 * @return Map */ @ExceptionHandler(NullPointerException.class) public Map<String,Object> nullPointerException(NullPointerException nullPointerException){ Map<String,Object> map = new HashMap<>(2); map.put("code",400); map.put("msg","空引用异常"); return map; } }@RestControllerAdvice注解到类上,@ExceptionHandler注解到具体的异常上,只有@ExceptionHandler注解的异常,才会进行处理,如上,系统只会处理IndexOutOfBoundsException以及NullPointerException异常,其他异常均不进行处理。使用/** * @author laughing * @date 2020/9/26 * @site https://www.xiangcaowuyu.net */ @RestController public class TestGlobalExceptionController { /** * 测试越界异常 * * @return String */ @RequestMapping("/testIndexOutOfBoundsException") public String testIndexOutOfBoundsException() { String[] names = {"张三"}; return names[2]; } /** * 测试空引用异常 * * @return String */ @RequestMapping("/testNullPointerException") public String testNullPointerException() { String firstName = null; String lastName = "laughing"; return firstName.toLowerCase() + lastName; } /** * 这个异常不会被处理 * * @return String */ @RequestMapping("/exception") public String testException() throws Exception { throw new Exception("这个异常不会被处理"); } }我们分别进行请求测试@InitBinder 全局数据预处理全局数据预处理可以在@RequestMapping方法前,先对数据进行处理,然后在进入@RequestMapping方法。定义全局数据预处理类/** * @author laughing * @date 2020/9/26 * @site https://www.xiangcaowuyu.net */ @RestControllerAdvice public class GlobalDataBinder { @InitBinder public void initBinder(WebDataBinder binder) { binder.registerCustomEditor(Date.class, new PropertyEditorSupport() { @Override public void setAsText(String text) { Date date = null; try { if (text != null) { date = DateUtils.addDays(DateUtils.parseDate(text,"yyyy-MM-dd"),1); } } catch (ParseException e) { } setValue(date); } }); } }使用 @ModelAttribute @RequestMapping("/testGlobalDataBinderController") public Person testGlobalDataBinderController(@RequestParam("name") String name, @RequestParam("birthday")Date birthday){ Person person = new Person(); person.setBirthday(birthday); person.setName(name); return person; } @ModelAttribute @RequestMapping("/testGlobalDataBinderControllerBody") public Person testGlobalDataBinderControllerBody(@RequestBody Person person){ return person; } }我们通过postman测试,可以发现日期已经自动加了一天@ModelAttribute 全局数据绑定全局数据绑定功能可以用来做一些初始化的数据操作,我们可以将一些公共的数据定义在添加了 @ControllerAdvice注解的类中,这样,在每一个 Controller 的接口中,就都能够访问导致这些数据。定义全局数据绑定/**@author laughing@date 2020/9/26@site https://www.xiangcaowuyu.net */@RestControllerpublic class TestGlobalDataAttributeController {/** * 全局数据绑定 * @author laughing * @date 2020/9/26 * @site https://www.xiangcaowuyu.net */ @RestControllerAdvice public class GlobalDataAttribute { @ModelAttribute(name = "person") public Map<String,Object> modelAttribute(){ Map<String,Object> map = new HashMap<>(); map.put("name","张三"); return map; } }使用全局数据绑定/** * @author laughing * @date 2020/9/26 * @site https://www.xiangcaowuyu.net */ @RestController public class TestGlobalDataAttributeController { /** * 测试 * @param person 绑定模型 * @return 绑定数据 */ @RequestMapping("/testGlobalDataAttribute") public Map<String, Object> testDataBinder(@ModelAttribute("person") Map<String, Object> person) { return person; } }
2020年09月27日
1,237 阅读
0 评论
0 点赞
2020-09-27
Spring Boot条件注解
什么是条件注解@Conditional 根据满足某一个特定条件创建一个特定的 Bean。就是根据特定条件来控制 Bean 的创建行为,这样我们可以利用这个特性进行一些自动的配置。Spring boot 中大量用到了条件注解简单实践以不同的操作系统作为条件,我们将通过实现 CommandCondition 接口,并重写其 matches() 方法来构造判断条件。若在 Windows 系统下运行程序,则输出列表命令为 dir ,若在 Linux 系统或者Mac下运行程序,则输出列表命令为 ls创建工程这里我们只创建简单的maven工程,而不是spring boot工程。打开idea,选择创建工程。向导界面,选择Maven→勾选create from archetype,选择org.apache.maven.archetypes:maven-archetype-quickstart输入工程信息设置maven引入依赖打开pom.xml文件,增加spring依赖 <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.9.RELEASE</version> </dependency>定义接口/** * 定义接口 * @author laughing * @date 2020/9/26 * @site https://www.xiangcaowuyu.net */ public interface CommandCondition { /** * 获取命令 * @return win返回dir,linux及mac返回ls */ public String getCommand(); }定义接口实现类定义三个接口实现类,分别继承CommandCondition接口/** * @author laughing * @date 2020/9/26 * @site https://www.xiangcaowuyu.net */ public class MacCommand implements CommandCondition{ /** * 获取命令 * * @return win返回dir,linux及mac返回ls */ @Override public String getCommand() { return "ls"; } }/** * @author laughing * @date 2020/9/26 * @site https://www.xiangcaowuyu.net */ public class LinuxCommand implements CommandCondition{ /** * 获取命令 * * @return win返回dir,linux及mac返回ls */ @Override public String getCommand() { return "ls"; } }/** * @author laughing * @date 2020/9/26 * @site https://www.xiangcaowuyu.net */ public class WindowsCommand implements CommandCondition{ /** * 获取命令 * * @return win返回dir,linux及mac返回ls */ @Override public String getCommand() { return "dir"; } }定义条件类定义三个条件类,分别实现matches() 方法,用来构造判断条件/** * @author laughing * @date 2020/9/26 * @site https://www.xiangcaowuyu.net */ public class LinuxCommandContidion implements Condition { @Override public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) { return Objects.requireNonNull(conditionContext.getEnvironment().getProperty("os.name")).contains("Linux"); } }/** * @author laughing * @date 2020/9/26 * @site https://www.xiangcaowuyu.net */ public class MacCommandContidion implements Condition { @Override public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) { return Objects.requireNonNull(conditionContext.getEnvironment().getProperty("os.name")).contains("Mac"); } }/** * @author laughing * @date 2020/9/26 * @site https://www.xiangcaowuyu.net */ public class WindowsCommandContidion implements Condition { @Override public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) { return Objects.requireNonNull(conditionContext.getEnvironment().getProperty("os.name")).contains("Windows"); } }定义配置类定义配置类,注入根据条件注入Bean/** * @author laughing * @date 2020/9/26 * @site https://www.xiangcaowuyu.net */ @Configuration public class CommandConfig { @Bean @Conditional(LinuxCommandContidion.class) public CommandCondition linuxCommand(){ return new LinuxCommand(); } @Bean @Conditional(MacCommandContidion.class) public CommandCondition macCommand(){ return new MacCommand(); } @Bean @Conditional(WindowsCommandContidion.class) public CommandCondition windowsCommand(){ return new WindowsCommand(); } }使用在main函数中,创建一个 AnnotationConfigApplicationContext 实例用来加载 Java 配置类,并注册我们的配置类,然后刷新容器。容器刷新完成后,我们就可以从容器中去获取 CommandCondition 的实例了,这个实例会根据操作系统不同,返回不同的命令。/** * Hello world! */ public class App { public static void main(String[] args) { AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(); annotationConfigApplicationContext.register(CommandConfig.class); annotationConfigApplicationContext.refresh(); CommandCondition commandCondition = annotationConfigApplicationContext.getBean(CommandCondition.class); String command = commandCondition.getCommand(); System.out.println(command); } }测试通过java -jar命令在不同操作系统分别运行jar包,查看输出java -jar conditional-1.0-SNAPSHOT-jar-with-dependencies.jar生成jar包运行说明jar包无法运行默认情况下,直接生成的jar包是没有配置入口类并且不包含依赖的。所以会报以下错误解决我们需要在pom.xml中增加打包插件maven-assembly-plugin<!-- 打包方式:mvn package assembly:single --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> <version>2.5.5</version> <configuration> <archive> <manifest> <mainClass>org.lisen.condition.App</mainClass> </manifest> </archive> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> </configuration> <executions> <execution> <id>make-assembly</id> <phase>package</phase> <goals> <goal>assembly</goal> </goals> </execution> </executions> </plugin>重新 mvn install我们会得到两个jar包,名称带-with-dependencies是包含依赖的,也是我们可以通过java -jar 命令运行的。参考资料条件注解,spring boot的基石
2020年09月27日
1,276 阅读
0 评论
0 点赞
2020-09-26
徒手撸一个Spring Boot Starter,学习自动化配置
what-are-spring-boot-starter-jars(spring boot中的starter是干啥的)Spring Boot Starter是在SpringBoot组件中被提出来的一种概念,stackoverflow上面已经有人概括了这个starter是什么东西,想看完整的回答戳这里下面摘抄一段Starter POMs are a set of convenient dependency descriptors that you can include in your application. You get a one-stop-shop for all the Spring and related technology that you need, without having to hunt through sample code and copy paste loads of dependency descriptors. For example, if you want to get started using Spring and JPA for database access, just include the spring-boot-starter-data-jpa dependency in your project, and you are good to go。扔到百度翻译里面翻译下:starter pom是一组方便的依赖描述符,可以包含在应用程序中。您可以获得所需的所有Spring和相关技术的一站式服务,而不必搜索示例代码和复制粘贴大量依赖描述符。例如,如果您想开始使用Spring和JPA进行数据库访问,只需在项目中包含springbootstarterdatajpa依赖项,就可以开始了。其实说白了,就是把一些重复的、机械的工作合成起来。如何自定义自己的starter其实starter也只是一个普通的maven工程,关于starter工程的命令,可以参考官方文档创建一个starter基本包含以下几个步骤:创建一个maven项目,关于项目的命名你可以参考考官方文档创建一个ConfigurationProperties用于保存你的配置信息增加starter实现类创建一个AutoConfiguration,引用定义好的配置信息把AutoConfiguration类加入spring.factories配置文件中进行声明打包项目并推送到maven仓库新建SpringBoot项目引入starter依赖并使用。下面的演示,我们创建一个starter,能够根据配置的url,打印并输出对应页面的内容,同时如果不传递参数,自动打印香草物语https://www.xiangcaowuyu.net的首页第一步创建工程并修改对应的xml文件创建工程后,需要修改对应的pom.xml文件,并增加依赖,具体修改内容如下:注意这里面的几个坑自定义的starter是不能有启动入口的!即:只能作为工具类!所以我们必须把启动类删除掉。否者,在依赖的工程里面无法引入类。需要把pom.xml的build节点全部删掉,不然无法install或者deploy。创建一个ConfigurationProperties用于保存你的配置信息先修改application.yaml文件,增加默认配置blog: url: https://www.xiangcaowuyu.net增加配置类,并注入配置文件/** * @author laughing * @date 2020/9/26 * @site https://www.xiangcaowuyu.net */ @ConfigurationProperties(prefix = "blog") public class BlogPropertes { private String url; public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } }增加starter实现类我的实现类只是简单的通过jsoup打印并返回一个html的内容。** * @author laughing * @date 2020/9/26 * @site https://www.xiangcaowuyu.net */ public class PrintHtmlService { public void setUrl(String url) { this.url = url; } private String url; /** * 打印并返回html内容 * @return * @throws IOException */ public String print() throws IOException { Document document = Jsoup.parse(new URL(this.url), 300 * 1000); String htmlString = document.html(); System.out.println(htmlString); return htmlString; } }创建一个AutoConfiguration,引用定义好的配置信息/** * @author laughing * @date 2020/9/26 * @site https://www.xiangcaowuyu.net */ @Configuration @EnableConfigurationProperties(BlogPropertes.class) @ConditionalOnClass(PrintHtmlService.class) public class AutoConfiguration { @Resource BlogPropertes blogPropertes; @Bean @ConditionalOnClass public PrintHtmlService printHtmlService(){ PrintHtmlService printHtmlService = new PrintHtmlService(); printHtmlService.setUrl(blogPropertes.getUrl()); return printHtmlService; } }@Configuration标识本类是配置类(相当于spring中application.xml)@EnableConfigurationProperties(AutoConfigruationProperties.class)如果AutoConfigruationProperties中有注解@ConfigurationProperties 那么这个类就会被加到spring上下文的容器中,也就是可以通过@Resource来注入@ConditionalOnClass当类路径下有指定类的情况下 才进行下一步@ConditionalOnMissingBean当spring容器中没有这个Bean的时候才进行下一步把AutoConfiguration类加入spring.factories配置文件中进行声明在resources文件夹增加META-INF在META-INF文件夹下增加spring.factories文件,并设置自动装配org.springframework.boot.autoconfigure.EnableAutoConfiguration = org.lisen.printhtmlstarter.config.AutoConfiguration打包项目并推送到maven仓库如果有maven私服,可以推送到远程仓库,我这里只是自己测试,所以直接install到自己本地仓库mvn package install新建SpringBoot项目引入starter依赖并使用我这里直接新建一个普通的web项目,加入pringt-html-starter依赖进行测试新建项目并加入依赖第一次我们先不重写默认的url新建一个测试类,代码如下:/** * @author laughing * @date 2020/9/26 * @site https://www.xiangcaowuyu.net */ @RestController public class TestController { @Resource PrintHtmlService printHtmlService; @RequestMapping("/print") public String print() throws IOException { return printHtmlService.print(); } }通过测试,我们可以发现,正常输入了默认的https://www.xiangcaowuyu.net的内容第二次我们修改配置文件,重写url为http://www.baidu.com修改配置文件如下,blog: url: https://www.baidu.com再次请求,我们发现,正常输出了百度的首页
2020年09月26日
1,104 阅读
0 评论
0 点赞
2020-09-24
Spring Boot配置文件详解
关于配置文件springboot有两种格式的配置文件,即yaml和properties,两种配置文件在功能上完全等效。相对于 properties而言,yaml更加简洁明了,而且使用的场景也更多。除了简洁,yaml还有另外一个特点,就是yaml中的数据是有序的,properties 中的数据是无序的关于yaml以及properties详细使用方法,我们稍后开贴专门说明,这里不再赘述。配置文件加载顺序默认情况下,springboot应用会依次从以下位置加载配置文件:项目根目录下的config文件夹项目根目录resources目录下的config文件夹resources目录这四个是默认的位置,我们可以简单验证一下。在项目根目录下config文件夹下的application.yaml,设置端口为6666server: port: 6666启动项目,我们可以看到,默认端口已经是6666自定义配置文件位置除了上述的四个默认加载配置文件的位置,我们也可以自定义文件位置。通过pring.config.location 即可指定加载配置文件位置Idea调试时动态指定配置文件位置举个栗子,我在resources文件夹下面建立一个blog文件夹,并将 application.yaml 文件放到blog文件夹下,同时设置端口为6666加入创建配置文件,并按照如下设置修改Idea配置信息spring.config.location=classpath:/blog/一定要注意配置文件位置,最后的/不能少,否则会报错运行程序,我们会发现端口变成了 6666运行jar包是动态指定配置文件位置除了在Idea调试,我们终归要将程序发不成jar包,那么jar包如何加载配置文件呢?我们是以上面的程序进行说明,此时,我们将配置文件单独拿出来,同时将resource\blog文件夹删掉。并通过mvn package将程序打包成jar包,打包后的jar包名称为properties-0.0.1-SNAPSHOT.jar ,然后我们将jar包及application.yaml文件放到一起。我们通过java -jar properties-0.0.1-SNAPSHOT.jar --spring.config.location = ./运行程序,通过控制台,我们可以看到此时端口仍然是6666,证明已经加载我们的配置文件。自定义配置文件名自定义配置文件名的方式,与自定义配置文件的方式类似,同时两个命令可以一起使用。spring.config.name这里只展示一下用java -jar命令运行的方式,我把application.yaml文件改成blog.yaml,内容不变。java -jar properties-0.0.1-SNAPSHOT.jar --spring.config.location=./ --spring.config.name=blog可以看到,程序依然以6666端口成功启动。自定义配置文件加载顺序上面说了工程内的配置文件就自定义配置文件,如果自定义配置文件与默认配置文件同时存在,那么springboot如何加载呢。新建工程修改application.propertes端口号改成1234package打包工程使用java -jar 命令加载配置文件,并制定端口为4321我们看到,程序先加载了环境变量中的配置信息
2020年09月24日
1,274 阅读
1 评论
0 点赞
2019-11-01
Spring Boot手工开启、回滚事务
添加注解@Autowired PlatformTransactionManager platformTransactionManager; @Autowired TransactionDefinition transactionDefinition;启用事务TransactionStatus transactionStatus = platformTransactionManager.getTransaction(transactionDefinition);提交事务platformTransactionManager.commit(transactionStatus);回滚事务platformTransactionManager.rollback(transactionStatus);
2019年11月01日
1,275 阅读
0 评论
0 点赞
2019-07-28
Spring Boot原生异步请求API说明
异步请求api调用说明在编写实际代码之前,我们来了解下一些关于异步请求的api的调用说明。获取AsyncContext:根据HttpServletRequest对象获取AsyncContext asyncContext = request.startAsync(); 设置监听器:可设置其开始、完成、异常、超时等事件的回调处理public interface AsyncListener extends EventListener { void onComplete(AsyncEvent event) throws IOException; void onTimeout(AsyncEvent event) throws IOException; void onError(AsyncEvent event) throws IOException; void onStartAsync(AsyncEvent event) throws IOException; }说明onStartAsync:异步线程开始时调用onError:异步线程出错时调用onTimeout:异步线程执行超时调用onComplete:异步执行完毕时调用一般上,我们在超时或者异常时,会返回给前端相应的提示,比如说超时了,请再次请求等等,根据各业务进行自定义返回。同时,在异步调用完成时,一般需要执行一些清理工作或者其他相关操作。需要注意的是只有在调用request.startAsync前将监听器添加到AsyncContext,监听器的onStartAsync方法才会起作用,而调用startAsync前AsyncContext还不存在,所以第一次调用startAsync是不会被监听器中的onStartAsync方法捕获的,只有在超时后又重新开始的情况下onStartAsync方法才会起作用。设置超时:通过setTimeout方法设置,单位:毫秒。一定要设置超时时间,不能无限等待下去,不然和正常的请求就一样了。Servlet方式实现异步请求面已经提到,可通过HttpServletRequest对象中获得一个AsyncContext对象,该对象构成了异步处理的上下文。所以,我们来实际操作下。编写一个简单控制层package Net.XiangCaoWuYu.Controllers; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.*; import javax.servlet.AsyncContext; import javax.servlet.AsyncEvent; import javax.servlet.AsyncListener; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * ClassName: AsyncController <br/> * Description: <br/> * date: 2019/7/28 16:06<br/> * * @author lisen01<br /> * @since JDK 1.8 */ @RestController @Api(tags = "测试异步请求") @ResponseBody @RequestMapping(value = "/AsyncTest") public class ServletAsyncController { private final static Logger logger = LoggerFactory.getLogger(ServletAsyncController.class); @PostMapping(value = "test") @ApiOperation(value = "测试异步请求") public void test(HttpServletRequest request, HttpServletResponse response) { AsyncContext context = request.startAsync(); context.addListener(new AsyncListener() { @Override public void onComplete(AsyncEvent asyncEvent) throws IOException { logger.info("执行完成"); } @Override public void onTimeout(AsyncEvent asyncEvent) throws IOException { logger.info("执行超时:"); } @Override public void onError(AsyncEvent asyncEvent) throws IOException { logger.info("发生错误:" + asyncEvent.getThrowable()); } @Override public void onStartAsync(AsyncEvent asyncEvent) throws IOException { logger.info("开始执行:"); } }); //设置超时 context.setTimeout(2000); //开启线程 context.start(new Runnable() { @Override public void run() { try{ Thread.sleep(100); logger.info("内部线程:"+Thread.currentThread().getName()); context.getResponse().setCharacterEncoding("UTF-8"); context.getResponse().setContentType("text/html;charset=utf-8"); context.getResponse().getWriter().println("这是内部线程"); //异步请求完成通知 //此时整个请求才完成 //其实可以利用此特性 进行多条消息的推送 把连接挂起。。 context.complete(); } catch (InterruptedException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }); //此时之类 request的线程连接已经释放了 logger.info("线程:" + Thread.currentThread().getName()); } }注意:异步请求时,可以利用ThreadPoolExecutor自定义个线程池使用过滤器时,需要加入asyncSupported为true配置,开启异步请求支持@WebServlet(urlPatterns = "/okong", asyncSupported = true ) public class AsyncServlet extends HttpServlet ...
2019年07月28日
1,306 阅读
0 评论
0 点赞
2019-07-28
Spring Boot自定义启动Banner
看烦了自带的Banner,动手修改一个属于自己的Banner,提现逼格的时候到了~哈哈,以下是官网给的配置指南:文字形式其实,替换很简单,只需要在classpath路径下创建一个banner.txt即可。具体的一些变量官网也有给出,具体如下:${AnsiColor.BRIGHT_YELLOW} //////////////////////////////////////////////////////////////////// // _ooOoo_ // // o8888888o // // 88" . "88 // // (| ^_^ |) // // O\ = /O // // ____/`---'\____ // // .' \\| |// `. // // / \\||| : |||// \ // // / _||||| -:- |||||- \ // // | | \\\ - /// | | // // | \_| ''\---/'' | | // // \ .-\__ `-` ___/-. / // // ___`. .' /--.--\ `. . ___ // // ."" '< `.___\_<|>_/___.' >'"". // // | | : `- \`.;`\ _ /`;.`/ - ` : | | // // \ \ `-. \_ __\ /__ _/ .-` / / // // ========`-.____`-.___\_____/___.-`____.-'======== // // `=---=' // // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ // // 佛祖保佑 永不宕机 永无BUG // //////////////////////////////////////////////////////////////////// 效果关闭banner如果需要关闭banner,可以通过设置SpringApplicationBuilder来设置bannerMode为OFF。 SpringApplicationBuilder builder = new SpringApplicationBuilder(DemoApplication.class); builder.bannerMode(Banner.Mode.OFF); builder.run(args);
2019年07月28日
1,210 阅读
0 评论
1 点赞
2019-07-28
Spring Boot热部署
但当服务功能一多,启动速度缓慢时,还是配置个热部署比较方便。在SpringBoot中,只需要加入一个spring-boot-devtools即可。<!-- 增加热部署--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> </dependency>若不生效,可试着在打包工具spring-boot-maven-plugin下的configuration加入true看看,具体配置项如下:<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <fork>true</fork> </configuration> </plugin> </plugins> </build>
2019年07月28日
1,404 阅读
0 评论
0 点赞
2019-07-28
Spring Boot配置跨域
同源策略很多人对跨域有一种误解,以为这是前端的事,和后端没关系,其实不是这样的,说到跨域,就不得不说说浏览器的同源策略。同源策略是由Netscape提出的一个著名的安全策略,它是浏览器最核心也最基本的安全功能,现在所有支持JavaScript的浏览器都会使用这个策略。所谓同源是指协议、域名以及端口要相同。同源策略是基于安全方面的考虑提出来的,这个策略本身没问题,但是我们在实际开发中,由于各种原因又经常有跨域的需求,传统的跨域方案是JSONP,JSONP虽然能解决跨域但是有一个很大的局限性,那就是只支持GET请求,不支持其他类型的请求,而今天我们说的CORS(跨域源资源共享)(CORS,Cross-origin resource sharing)是一个W3C标准,它是一份浏览器技术的规范,提供了Web服务从不同网域传来沙盒脚本的方法,以避开浏览器的同源策略,这是JSONP模式的现代版。在Spring框架中,对于CORS也提供了相应的解决方案,今天我们就来看看SpringBoot中如何实现CORS。前端请求<!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <script src="jquery.min.js"></script> </head> <body> <div id="myDiv"></div> <script> $(document).ready(function () { $.ajax({ url: "http://localhost:8080/CrossOrigin", type:"post", async: false, success:function(data){ $("#myDiv").html(data); } }); }); </script> </body> </html>配置后端/** * @author laughing * @date 2020/9/26 * @site https://www.xiangcaowuyu.net */ @RestController public class CorsController { /** * 方法配置跨域 * @return String */ @RequestMapping("/CrossOrigin") public String crossOrigin(){ return "crossOrigin"; } }打开前端页面,我们可以看一下,报错信息如下,也就是出现了跨域通过CrossOrigin配置跨域我们可以将@CrossOrigin注解到方法上,实现跨域请求,我们对后端方法改造如下:/** * @author laughing * @date 2020/9/26 * @site https://www.xiangcaowuyu.net */ @RestController public class CorsController { /** * 方法配置跨域 * @return String */ @RequestMapping("/CrossOrigin") @CrossOrigin(origins = "http://localhost:1234") public String crossOrigin(){ return "crossOrigin"; } }通过CorsFilter配置跨域继续后端改造修改yaml文件,增加跨域配置信息#配置跨域 cors: allowedOrigin: - http://localhost:1234 allowCredentials: - true allowMethods: - GET - POST - PUT - DELETE maxAge: 7200 path: /** 增加CrosFilter配置文件package org.lisen.cors.config; import lombok.Getter; import lombok.Setter; import org.springframework.boot.context.properties.ConfigurationProperties; 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; import java.util.List; /** * 跨域配置 * * @author laughing * @date 2020/9/26 * @site https://www.xiangcaowuyu.net */ @Configuration @ConfigurationProperties(prefix = "cors") @Getter @Setter public class CorsFilterConfig { private boolean allowCredentials; private List<String> allowedOrigin; private List<String> allowMethods; private long maxAge; private String path; /** * 配置跨域 * * @return CorsFilter */ @Bean public CorsFilter corsFilter() { CorsConfiguration corsConfiguration = new CorsConfiguration(); this.allowedOrigin.forEach(corsConfiguration::addAllowedOrigin); this.allowMethods.forEach(corsConfiguration::addAllowedMethod); corsConfiguration.setAllowCredentials(this.allowCredentials); corsConfiguration.setMaxAge(this.maxAge); UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource(); urlBasedCorsConfigurationSource.registerCorsConfiguration(this.path, corsConfiguration); return new CorsFilter(urlBasedCorsConfigurationSource); } } 增加请求/** * @author laughing * @date 2020/9/26 * @site https://www.xiangcaowuyu.net */ @RestController public class CorsController { /** * 方法配置跨域 * @return String */ @RequestMapping("/CrossOrigin") // @CrossOrigin(origins = "http://localhost:1234") public String crossOrigin(){ return "crossOrigin"; } }再次请求,可以发现仍然能够正常访问通过WebMvcConfigurer配置跨域@Configuration public class MyWebMvcConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/cors/**") .allowedHeaders("*") .allowedMethods("*") .maxAge(1800) .allowedOrigins("http://localhost:8081"); } }
2019年07月28日
1,178 阅读
0 评论
0 点赞
2019-07-28
Spring Boot基于FileUpload包方式上传多个文件
添加万恶的依赖<!-- 附件上传--> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.3</version> </dependency>修改配置文件,屏蔽servlet自带的附件上传#配置上传文件信息 http: multipart: # 最大支持文件大小 即单个文件大小 max-file-size: 2m # 最大支持请求大小 即一次性上传的总文件大小 max-request-size: 10m #取消Servlet自带的上传 enabled: false 增加控制器package Net.XiangCaoWuYu.Controllers; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.util.ResourceUtils; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletRequest; import java.io.File; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; /** * ClassName: CommonsFileUpload <br/> * Description: <br/> * date: 2019/7/28 9:28<br/> * * @author lisen01<br /> * @since JDK 1.8 */ @RestController @ResponseBody @RequestMapping(value = "/commonsfileupload") public class CommonsFileUpload { private static final Logger logger = LoggerFactory.getLogger(CommonsFileUpload.class); @PostMapping("/upload") public String Upload(@RequestParam MultipartFile[] files, @RequestParam String name, HttpServletRequest request) throws IOException { if (files.length <= 0) { return "请先选择要上传的附件"; } for (MultipartFile file : files) { if (file.isEmpty()) { return "文件信息不能为空"; } String fileType = file.getContentType(); String fileName = file.getName(); String fileOriginalName = file.getOriginalFilename(); //String fileSavePath = request.getServletContext().getRealPath("/static/sources"); //使用jar包,放到同级目录 File rootPath = new File(ResourceUtils.getURL("classpath:").getPath()); String fileSavePath = rootPath.getAbsolutePath()+"/static/upload/"; Date date = new Date(); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); fileSavePath = fileSavePath + simpleDateFormat.format(date); fileSavePath = fileSavePath + "/" + fileOriginalName; fileSavePath.replace("/", File.separator); File saveFile = new File(fileSavePath); if (!saveFile.getParentFile().exists()) { saveFile.getParentFile().mkdirs(); } file.transferTo(saveFile); } return "上传成功"; } }
2019年07月28日
1,053 阅读
0 评论
0 点赞
2019-07-28
Spring Boot使用J2EE上传文件
温馨提示这种方式下,其实无需任何配置。只需按正常的web开发项目集成即可添加普通web项目依赖<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>修改配置文件(可选)配置上传文件信息 http: multipart: # 最大支持文件大小 即单个文件大小 max-file-size: 2m # 最大支持请求大小 即一次性上传的总文件大小 max-request-size: 10m 使用package Net.XiangCaoWuYu.Controllers; import com.sun.jmx.snmp.agent.SnmpMibAgent; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletRequest; import java.io.File; import java.io.IOException; import java.nio.file.Paths; import java.text.SimpleDateFormat; import java.util.Date; @RestController public class J2EEFileUpload { private static final Logger logger = LoggerFactory.getLogger(J2EEFileUpload.class); @PostMapping("/upload") @ResponseBody public String UploadFile(@RequestParam MultipartFile file, HttpServletRequest request) throws IOException { if (file.isEmpty()) { return "上传文件不能为空"; } String fileType = file.getContentType(); String fileName = file.getName(); String originalName = file.getOriginalFilename(); long fileSize = file.getSize(); logger.info("原始文件名为:" + originalName); logger.info("服务器文件名为:" + fileName); logger.info("文件大小为:" + String.valueOf(fileSize)); String fileSavePath = request.getServletContext().getRealPath("/static/upload/"); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-ddd"); fileSavePath = fileSavePath + simpleDateFormat.format(new Date())+"//"; fileSavePath = fileSavePath.replace("//",File.separator); File saveFile = new File(fileSavePath+originalName); if(!saveFile.getParentFile().exists()){ saveFile.getParentFile().mkdirs(); } file.transferTo(saveFile); return "上传成功"; } }
2019年07月28日
1,127 阅读
0 评论
0 点赞
1
...
6
7
8