SpringBoot(四)——SpringBoot 异常处理、配置拦截器、自定义banner、三种跨域处理、AOP 的应用、文件上传、整合 Web 基础组件、整合 JdbcTemplate和多数据源
一、SpringBoot 异常处理
在 SpringBoot 中,相对于 MVC ,SpringBoot 的异常处理简便的多,因为很多东西已经封装好了。
1、默认的异常处理
a、系统页面
SpringBoot 已经帮我们做好了异常处理,当运行一个 SpringBoot 项目时,直接手动触发一个错误,可以发现这个错误的页面跟以往的都不一样,这就是 SpringBoot 帮我们处理的异常:
这个 404 页面跟以往的都不同。因为这就是默认的异常处理。
b、自定义页面(静态页面)
如果有想要触发异常时用的是自己写的页面,也可以,自定义页面分静态页面和动态页面。
在 static 文件夹下创建 error ,那么触发异常时就会到这个文件夹下寻找对应的页面:
如果触发的是 4开头的错误,比如 401,402,403,404 等,那么触发错误时就会进到这个 4xx.html 页面来。同理,5xx.html 也是一样的。
如果有专门处理 404 错误的页面 404.html,那么即便有 4xx.html 页面的情况下,触发 404 异常时会优先到 404.html 里面来。
c、自定义页面(动态页面)
如果想要展示动态页面,或者数据是动态的,就在 templates 文件夹下创建 error 文件夹,接着操作跟上面的一样:
用的模板是 Thymeleaf。
然后看效果:
d、部分源码理解
来看下源码:
很多异常信息都是上面这个方法提供的。
除了上面展示的,其实还有一些信息没有展示:
上图中左边的那部分信息如果像右边那样写是展示不出来:
效果:
为什么显示不出来呢?
本来获取的时候是有这些信息的( errorAttributes ),但是下面的 if 那部分,就移除了这些信息了。
可以发现 options 都移除掉了部分异常信息;那么怎么让 options 不移除掉这些信息呢?
可以在 application.properties 里面控制:
效果:
此时异常信息是没有的,那么可以在地址栏控制:
这么输入,就会出现异常信息了。
e、小结
2、自定义异常信息(数据)
自定义不建议去实现接口,因为比较麻烦,需要自己去收集信息,相当于从 0 开始。
比较推荐继承,因为已经把异常信息已经收集好了。
3、自定义异常视图
如果想自定义异常视图,不想放在 error 文件夹里,可以这样:
这样,如果有异常就会进 qf 文件夹里面。
那么这里的 model 可以获取异常信息并且修改这个 model 吗,答案是不行:
二、SpringBoot 其他配置
1、配置拦截器(Java 代码)
拦截器跟 MVC 的时候是一样的。
先写好一个拦截器:
接着就是注册:
2、配置拦截器(XML 配置)
正常来说不需要 xml 配置,但是如果是整合一些旧的项目,想要引入 xml 配置,也是支持的。
先写一个 xml 配置:
接着在 java 代码那里加载:
3、自定义 banner
什么是 banner 呢,就是启动 SpringBoot 项目的时候,那个横幅就是了:
这玩意就是 banner,那么如果想要改变这玩意,怎么改变呢?
在 resources 文件夹下,新建一个 banner.txt ,里面写上自己想要的东西即可:
如果不想要的话,也可以关闭:
在启动项目的文件那里这么写即可关闭。
4、三种跨域处理
a、局部配置
跟 MVC 的处理是基本一样的。
开两个 IDEA,设置一个 8081 端口,一个 8080 端口,用客户端访问服务端,正常情况下是不能访问的,因为有跨域拦截,加一个注解即可解决。
但是普通情况下,即便加了注解,如果没有其他设置,put 和 delete 还是不能请求的。
点 get 和 post 的时候,是只有一个请求的,如果点 put 会有两个请求:
可以看到这里的请求不是 put ,反而是个 options。
put 和 delete 是复杂请求,需要先探测,先发送一个探测请求(options),探测请求的目的是为了检查服务端是否支持当前请求的处理。探测请求不用每一次都发送,它有有效期,例如半小时,即探测请求发送之后,半小时之内,不用再次发送。
如果禁用了缓存,则每次都需要探测。
b、全局配置跨域
c、自定义跨域过滤器
跨域是怎么解决的呢?
其实只要在响应头中,加入上图中的红圈部分,就能够解决跨域了。
其实上面做的方式在底层中,就是个过滤器,过滤器叫 CorsFilter。
可以自定义跨域过滤器:
5、AOP 的应用
a、AOP 的使用
要在 SpringBoot 中使用 AOP,需要先加一个依赖:
先写一个接口和实现类:
接着开始配置切面:
然后测试代码:
运行没问题。
如果要定义另外四个通知,可参考前面的博客。使用方式是一模一样的。
b、版本和 CGLib 与 jdk 之间的关系
以前说过,如果有接口,就用 jdk 动态代理,如果没有接口,就用 CGLib 动态代理。但是目前用的是接口,经测试可知用的是 CGLib,那么 SpringBoot 的底层到底是用哪个呢?这涉及到版本的问题,不同版本有区别:
如果这里设置成 jdk 的话,则这里需要改:
来看下底层动态代理的实现条件:
6、文件上传
跟 MVC 比起来,非常容易,几乎不用加什么,直接写代码即可。
SimpleDateFormat sdf = new SimpleDateFormat("/yyyy/MM/dd/");
@PostMapping("/upload")
public String upload(MultipartFile file, String name, HttpServletRequest req){
System.out.println("name = "+name);
// 1.获取文件保存路径
String format = sdf.format(new Date());
// 获取项目运行路径 + 日期 组成一个完整路径
String realPath = req.getServletContext().getRealPath("/img") + format;
System.out.println(realPath);
File folder = new File(realPath);
if (!folder.exists()){
folder.mkdirs();
}
// 2.文件重命名
String oldName = file.getOriginalFilename();
String newName = UUID.randomUUID().toString() + oldName.substring(oldName.lastIndexOf("."));
// 保存文件
try {
file.transferTo(new File(folder,newName)); // 第一个参数是文件夹,第二个参数是文件名。
// 返回文件路径
String url = req.getScheme()+"://"+req.getServerName() + ":" + req.getServerPort() + req.getContextPath() + "/img" + format + newName;
System.out.println("url="+url);
return url;
} catch (IOException e) {
e.printStackTrace();
}
return "error";
文件下载这里就不写了,跟之前 MVC 是一模一样的。
文件上传还有大小各种限制,那么写在哪里呢:
7、整合 Web 基础组件
SpringBoot 整合 servlet,意思是 SpringBoot 中怎么使用 servlet 里面的东西;其实很简单,就一个注解的事:
servlet 和 filter 和 Listener;filter 可以用上面那种用法。
但是即便加了注解,也不会扫描这些的,所以还需要一个注解:
这么加了以后,就没有问题了。
三、SpringBoot 整合持久化框架
1、整合 JdbcTemplate
a、创建与使用
创建项目:
有一点要注意的是:
可以发现没有版本号,那必然是自动安装的最新版本的了,如果版本比较老,则需要手动输入版本号!
虽然不一定连不上,但是有时候就是连不上。
接着就是配置数据库信息:
然后开始按照数据库表创建实体类:
测试代码:
结果:
可以看到能成功使用。
b、额外提供的分页功能
然后重新测试,就会发现已经分页:
其他的增删改查就基本一样的,这里就不演示了。
2、整合 JdbcTemplate 多数据源
比如插入从数据库1插入,但是读数据在数据库2读,这就是多数据源的一个使用。
a、配置多数据源
先导入一个 druid 依赖,用这个处理会比较方便一点:
接着不能使用系统提供的数据源,要使用自己定义的数据源:
然后 JdbcTemplate 也是要自己去配:
当然,还有另外一种写法:
然后测试代码:
然后最终结果: