是什么:对spring的简化,自动装配,开箱即用,关注业务本身而你不是xml配置,甚至不配置将常用功能场景集成到一个个start,更加容易搭建web工程,适合开发微服务,自动配置,独立容器
spring组件是轻量级但是配置切是重量级别的,后来引入注解但是配置还是不少,而且存在版本冲突
将常用的功能封装成一个个start,需要什么就导入依赖
<!--导入配置文件处理器,配置文件进行绑定就会有提示-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
@RequestParam
@GetMapping("/hello")
public String hello(@RequestParam(value = "name", defaultValue = "World") String name) {
return String.format("Hello %s!", name);
}
http://localhost:8080/hello 返回Hello World!
http://localhost:8080/hello?name=Amy 返回Hello Amy!
@EnableAutoConfiguration 开启依赖自动化配置
@SpringBootApplication 来标注一个主程序类,说明这是一个Spring Boot应用
@ConfigurationProperties(prefix = “person”) 配置文件值注入
@ComponentScan 同级包或者子包扫描
@自动以configuration创建配置,代替配置文件
@ConfigurationPropertie可以安全注入
配置类@Configuration------>Spring配置文件 、使用@Bean给容器中添加组件
@Configuration
public class AllConfiguration extends WebMvcConfigurerAdapter{
//准备框架中需要维护的拦截器对象<bean>
@Bean
public CartInterceptor cartIntInit(){
return new CartInterceptor();
}
}
@Configuration//spring-config.xml
//@ImportResource(value="classpath:spring.xml")
public class Demo01Config {
//<bean id="haha" class="org.springframework.web.client.RestTemplate"/>
@Bean(value="haha") //相当于bean标签
public RestTemplate initTemplate(){
return new RestTemplate();
}
//将读取的<bean标签转化成代码实现
//<bean class="com.jt.component.Demo01Component"></bean>
@Bean //如果不设置value,将会默认以方法名称作为当前内存bean的id使用
public Demo01Component initComponent(){
return new Demo01Component();
}
}
//属性读取注入到对象中,springboot容器一旦加载
//appcation.properties,@Value必须在扫描范围内的类中使用
@Value("${userUserName}")
private String userName;
@Value("${age}")
private Integer age;
@Value("${id}")
private Integer id;
@RequestMapping("springboot/test03")
public User test03(String name){
User user=new User();
user.setAge(age);
user.setId(id);
user.setName(name);
return user;
}
如果是非appcation.properties,book.properties则需要@PropertySource引入资源,yml不支持
@SpringBootApplication是一个组合注解包括:
- @SpringBootConfiguration
- @Configuration配置类
- @EnableAutoConfiguration自动配置
- @ComponentScan包扫描——同级或者子包下
banner定制
在资源目录下新建一个banner.txt文件
http://patorjk.com/software/taag 在这个网站制作
springboot多环境(dev,test,prod)配置
- application.properties 配置
- application-dev.properties 配置(开发环境配置)
- application-test.properties 配置(测试环境配置)
- application-prod.properties 配置(生产环境配置)
通过修改application.properties文件spring.profiles.active参数决定加载对应环境的配置如:
spring.profiles.active=dev,启动开发配置环境
Json处理
spring-boot-starter-web整合了Jackson,所以springboot工程可以拿来直接使用,直接在方法上加 @ResponseBody注解或者在类上加@RestController
@RestController是一个组合注解:
- @Controller
- @ResponseBody
HttpMessageConverter ,看名字就知道,这是一个消息转换工具,有两方面的功能:
- 将服务端返回的对象序列化成 JSON 字符串
- 将前端传来的 JSON 字符串反序列化成 Java 对象
所有的 JSON 生成都离不开相关的 HttpMessageConverter
SpringMVC 自动配置了 Jackson 和 Gson 的 HttpMessageConverter,Spring Boot 中又对此做了自动化配置:
- org.springframework.boot.autoconfigure.http.JacksonHttpMessageConvertersConfiguration
- org.springframework.boot.autoconfigure.http.GsonHttpMessageConvertersConfiguration
所以,如果用户使用 jackson 和 gson 的话,没有其他额外配置,则只需要添加依赖即可。
利用jackson序列化和反序列化
- ObjectMapper mapper = new ObjectMapper();
- String json = mapper.writeValueAsString(product);
- Product product = mapper.readValue(json, Product.class);
如果想使用Gson或者FastJson需要去除默认jackson的依赖导入相应的依赖入:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-json</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- <dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.49</version>
</dependency>
访问静态资源
springboot工程默认静态资源放在五个地方:
- classpath:/META-INF/resources/
- classpath:/resources/
- classpath:/static/
- classpath:/public/
- /
实际上/static/已经够用了
自定义访问路径
spring.resources.static-locations=classpath:/
spring.mvc.static-path-pattern=/**
第一行配置表示定义资源位置,第二行配置表示定义请求 URL 规则。以上文的配置为例,如果我们这样定义了,表示可以将静态资源放在 resources目录下的任意地方,我们访问的时候当然也需要写完整的路径,例如在resources/static目录下有一张名为1.png 的图片,那么访问路径就是 http://localhost:8080/static/1.png ,注意此时的static不能省略。
Java 代码定义
@Configuration
public class WebMVCConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**").addResourceLocations("classpath:/aaa/");
}
}
文件上传
单文件上传:
SimpleDateFormat sdf = new SimpleDateFormat("/yyyy/MM/dd/");
@PostMapping("/upload")
public String upload(MultipartFile file, HttpServletRequest req) {
String format = sdf.format(new Date());
String realPath = req.getServletContext().getRealPath("/img") + format;
File folder = new File(realPath);
if (!folder.exists()) {
folder.mkdirs();
}
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() + "/img" + format + newName;
return url;
} catch (IOException e) {
e.printStackTrace();
}
return "error";
}
多文件上传:
@PostMapping("/uploads")
public String uploads(MultipartFile[] files, HttpServletRequest req) {
String format = sdf.format(new Date());
String realPath = req.getServletContext().getRealPath("/img") + format;
File folder = new File(realPath);
if (!folder.exists()) {
folder.mkdirs();
}
for (MultipartFile file : files) {
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() + "/img" + format + newName;
System.out.println(url);
} catch (IOException e) {
e.printStackTrace();
}
}
return "success";
}
Ajax上传:
<body>
<div id="result"></div>
<input type="file" id="file">
<input type="button" value="上传" onclick="uploadFile()">
<script>
function uploadFile() {
var file = $("#file")[0].files[0];
var formData = new FormData();
formData.append("file", file);
$.ajax({
type:'post',
url:'/upload',
processData:false,
contentType:false,
data:formData,
success:function (msg) {
$("#result").html(msg);
}
})
}
</script>
</body>
@ControllerAdvice
@ControllerAdvice ,很多初学者可能都没有听说过这个注解,实际上,这是一个非常有用的注解,顾名思义,这是一个增强的 Controller。使用这个 Controller ,这是 SpringMVC 提供的功能,在 Spring Boot 中可以直接使用,下面分别来看。可以实现三个方面的功能:
- 全局异常处理
- 全局数据绑定
- 全局数据预处理
全局异常处理:
@ControllerAdvice
public class MyGlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public ModelAndView customException(Exception e) {
ModelAndView mv = new ModelAndView();
mv.addObject("message", e.getMessage());
mv.setViewName("myerror");
return mv;
}
}
在该类中,可以定义多个方法,不同的方法处理不同的异常,例如专门处理空指针的方法、专门处理数组越界的方法…,也可以直接向上面代码一样,在一个方法中处理所有的异常信息。
@ExceptionHandler 注解用来指明异常的处理类型,即如果这里指定为 NullpointerException,则数组越界异常就不会进到这个方法中来。
全局数据绑定
全局数据绑定功能可以用来做一些初始化的数据操作,我们可以将一些公共的数据定义在添加@ControllerAdvice 注解的类中,这样,在每一个 Controller 的接口中,就都能够访问导致这些数据。
使用步骤,首先定义全局数据,如下:
@ControllerAdvice
public class GlobalData {
@ModelAttribute(value = "info")
public Map<String,Object> mydata() {
Map<String, Object> map = new HashMap<>();
map.put("name", "javaboy");
map.put("address", "www.javaboy.org");
return map;
}
}
使用 @ModelAttribute 注解标记该方法的返回数据是一个全局数据,默认情况下,这个全局数据的 key 就是返回的变量名,value 就是方法返回值,当然开发者可以通过 @ModelAttribute 注解的 name 属性去重新指定 key。
@GetMapping("/hello")
public String hello(Model model) {
Map<String, Object> map = model.asMap();
Set<String> keySet = map.keySet();
for (String key : keySet) {
System.out.println(key + ":" + map.get(key));
}
return "hello";
}
全局数据预处理
考虑有两个实体类,Book 和 Author,分别定义如下:
public class Book {
private String name;
private Double price;
public String getName() {
return name;
}
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", price=" + price +
'}';
}
public void setName(String name) {
this.name = name;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
}
public class Author {
private String name;
private Integer age;
public String getName() {
return name;
}
@Override
public String toString() {
return "Author{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
@RestController
public class BookController {
@PostMapping("/book")
public void addBook(@ModelAttribute("b") Book book, @ModelAttribute("a") Author author) {
System.out.println(book);
System.out.println(author);
}
}
@ControllerAdvice
public class GlobalData {
@ModelAttribute(value = "info")
public Map<String,Object> mydata() {
Map<String, Object> map = new HashMap<>();
map.put("name", "javaboy");
map.put("address", "www.javaboy.org");
return map;
}
@InitBinder("a")
public void initA(WebDataBinder binder) {
binder.setFieldDefaultPrefix("a.");
}
@InitBinder("b")
public void initB(WebDataBinder binder) {
binder.setFieldDefaultPrefix("b.");
}
}
这样请求参数接上相应前缀就可以避免参数混淆
自定义异常
在 Spring Boot 项目中 ,异常统一处理,可以使用 Spring 中 @ControllerAdvice 来统一处理,也可以自己来定义异常处理方案。Spring Boot 中,对异常的处理有一些默认的策略
默认情况下,Spring Boot 中的异常页面 是这样的:
从这个异常提示中,也能看出来,之所以用户看到这个页面,是因为开发者没有明确提供一个 /error 路径,如果开发者提供了 /error 路径 ,这个页面就不会展示出来,不过在 Spring Boot 中,提供 /error 路径实际上是下下策,Spring Boot 本身在处理异常时,也是当所有条件都不满足时,才会去找 /error 路径。那么就先来看看,在 Spring Boot 中,如何自定义 error 页面,整体上来说,可以分为两种,一种是静态页面,另一种是动态页面。
静态异常页面
自定义静态异常页面,又分为两种,第一种 是使用 HTTP 响应码来命名页面,例如 404.html、405.html、500.html ….,另一种就是直接定义一个 4xx.html,表示400-499 的状态都显示这个异常页面,5xx.html 表示 500-599 的状态显示这个异常页面。
默认是在 classpath:/static/error/ 路径下定义相关页面:
此时,启动项目,如果项目抛出 500 请求错误,就会自动展示 500.html 这个页面,发生 404 就会展示 404.html 页面。如果异常展示页面既存在 5xx.html,也存在 500.html ,此时,发生500异常时,优先展示 500.html 页面。动态异常页面
动态的异常页面定义方式和静态的基本 一致,可以采用的页面模板有 jsp、freemarker、thymeleaf。动态异常页面,也支持 404.html 或者 4xx.html ,但是一般来说,由于动态异常页面可以直接展示异常详细信息,所以就没有必要挨个枚举错误了 ,直接定义 4xx.html(这里使用thymeleaf模板)或者 5xx.html 即可。
注意,动态页面模板,不需要开发者自己去定义控制器,直接定义异常页面即可 ,Spring Boot 中自带的异常处理器会自动查找到异常页面。
页面定义如下:
页面内容如下:
默认情况下,完整的异常信息就是这5条,展示 效果如下 :
如果动态页面和静态页面同时定义了异常处理页面,例如 classpath:/static/error/404.html 和 classpath:/templates/error/404.html 同时存在时,默认使用动态页面。即完整的错误页面查找方式应该是这样:
发生了500错误–>查找动态 500.html 页面–>查找静态 500.html –> 查找动态 5xx.html–>查找静态 5xx.html。
自定义异常数据
默认情况下,在Spring Boot 中,所有的异常数据其实就是上文所展示出来的5条数据,这5条数据定义在 org.springframework.boot.web.reactive.error.DefaultErrorAttributes 类中,具体定义在 getErrorAttributes 方法中 :
DefaultErrorAttributes 类本身则是在org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration 异常自动配置类中定义的,如果开发者没有自己提供一个 ErrorAttributes 的实例的话,那么 Spring Boot 将自动提供一个ErrorAttributes 的实例,也就是 DefaultErrorAttributes 。
基于此 ,开发者自定义 ErrorAttributes 有两种方式 :
- 直接实现 ErrorAttributes 接口
- 继承 DefaultErrorAttributes(推荐),因为 DefaultErrorAttributes 中对异常数据的处理已经完成,开发者可以直接使用。
具体定义如下:
定义好的 ErrorAttributes 一定要注册成一个 Bean ,这样,Spring Boot 就不会使用默认的 DefaultErrorAttributes 了,运行效果如下图:
自定义异常视图
异常视图默认就是前面所说的静态或者动态页面,这个也是可以自定义的,首先 ,默认的异常视图加载逻辑在 org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController 类的 errorHtml 方法中,这个方法用来返回异常页面+数据,还有另外一个 error 方法,这个方法用来返回异常数据(如果是 ajax 请求,则该方法会被触发)。
在这里,首先以异常响应码作为视图名分别去查找动态页面和静态页面,如果没有查找到,则再以 4xx 或者 5xx 作为视图名再去分别查找动态或者静态页面。
要自定义异常视图解析,也很容易 ,由于 DefaultErrorViewResolver 是在 ErrorMvcAutoConfiguration 类中提供的实例,即开发者没有提供相关实例时,会使用默认的 DefaultErrorViewResolver ,开发者提供了自己的 ErrorViewResolver 实例后,默认的配置就会失效,因此,自定义异常视图,只需要提供 一个 ErrorViewResolver 的实例即可:
实际上,开发者也可以在这里定义异常数据(直接在 resolveErrorView 方法重新定义一个 model ,将参数中的model 数据拷贝过去并修改,注意参数中的 model 类型为 UnmodifiableMap,即不可以直接修改),而不需要自定义MyErrorAttributes。定义完成后,提供一个名为123的视图,如下图:
模板引擎thymeleaf
添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
配置1
thymeleaf:
cache: false
check-template-location: true
encoding: UTF-8
mode: HTML5
prefix: classpath:/templates/
servlet:
content-type: text/html
suffix: .html
在templates编写模板
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<table border="1">
<tr>
<td>编号</td>
<td>用户名</td>
<td>地址</td>
</tr>
<tr th:each="user : ${users}">
<td th:text="${user.id}"></td>
<td th:text="${user.name}"></td>
<td th:text="${user.address}"></td>
</tr>
</table>
</body>
</html>
控制层代码
@GetMapping("/test")
//@CrossOrigin(value = "http://localhost:8093")
public String test(Model model){
List<user> users=new ArrayList<>();
for (int i=0;i<=10;i++){
user user=new user();
user.setId(i);
user.setName("深圳");
user.setAddress("有");
users.add(user);
}
model.addAttribute("users",users);
return "test";
}
CROS跨域
同源策略
同源策略是由Netscape提出的一个著名的安全策略,它是浏览器最核心也最基本的安全功能,现在所有支持JavaScript的浏览器都会使用这个策略。所谓同源是指协议、域名以及端口要相同。同源策略是基于安全方面的考虑提出来的,这个策略本身没问题,但是在实际开发中,由于各种原因又经常有跨域的需求,传统的跨域方案是JSONP,JSONP虽然能解决跨域但是有一个很大的局限性,那就是只支持GET请求,不支持其他类型的请求,而今天说的CORS(跨域源资源共享)(CORS,Cross-origin resource sharing)是一个W3C标准,它是一份浏览器技术的规范,提供了Web服务从不同网域传来沙盒脚本的方法,以避开浏览器的同源策略,这是JSONP模式的现代版。
在Spring框架中,对于CORS也提供了相应的解决方案,看看SpringBoot中如何实现CORS。
新建两个工程,8081和8082,通过springboot实现8081访问8080的接口,8081静态资源目录新建一个html文件
<div id="app"></div>
<input type="button" onclick="btnClick()" value="get_button">
<input type="button" onclick="btnClick2()" value="post_button">
<script>
function btnClick() {
$.get('http://localhost:8080/hello', function (msg) {
$("#app").html(msg);
});
}
function btnClick2() {
$.post('http://localhost:8080/hello', function (msg) {
$("#app").html(msg);
});
}
</script>
在8080添加同源注解
@RestController
public class HelloController {
@CrossOrigin(value = "http://localhost:8081")
@GetMapping("/hello")
public String hello() {
return "hello";
}
@CrossOrigin(value = "http://localhost:8081")
@PostMapping("/hello")
public String hello2() {
return "post hello";
}
}
这样就能跨域访问了
拦截器
编写拦截器
/**
* @author yuzb
* @date 2020/5/20 13:59
* @description
*/
public class MyInterceptor implements HandlerInterceptor {
/*
* @Description 该方法在控制器的处理请求方法前执行
* @Return boolean true 表示继续向下执行,返回 false 表示中断后续
* @Author yuzb
* @throws Exception
* @Date 2020/5/20 14:02
**/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle方法在控制器的处理请求方法调用之后,解析视图之前执行");
return true;
}
/*
* @Description 解析试图视图之前调用
* @Return void
* @Author yuzb
* @throws Exception
* @Date 2020/5/20 14:03
**/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle方法在控制器的处理请求方法调用之后,解析视图之前执行");
}
/*
* @Description 视图渲染结束后执行
* @Return void
* @Author yuzb
* @throws Exception
* @Date 2020/5/20 14:04
**/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion方法在控制器的处理请求方法执行完成后执行,即视图渲染结束之后执行");
}
}
注册拦截器
```java
/**
* @author yuzb
* @date 2020/5/20 14:06
* @description
*/
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(myInterceptor()).addPathPatterns("/test/**");
}
@Bean
MyInterceptor myInterceptor() {
return new MyInterceptor();
}
}
系统启动任务
系统启动时要做的操作
第一种 CommandLineRunner
@Component
@Order(99)
public class MyCommandLineRunner1 implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("MyCommandLineRunner1>>>"+ Arrays.toString(args));
}
}
@Component
@Order(98)
public class MyCommandLineRunner2 implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("MyCommandLineRunner2>>>"+ Arrays.toString(args));
}
}
@Component
@Order(99)
public class MyCommandLineRunner1 implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("MyCommandLineRunner1>>>"+ Arrays.toString(args));
}
}
@Order(99)数字越大执行越靠后,优先级的值为 Integer.MAX_VALUE,表示优先级最低
第二种ApplicationRunner
ApplicationRunner 和 CommandLineRunner 功能一致,用法也基本一致,唯一的区别主要体现在对参数的处理上,ApplicationRunner 可以接收更多类型的参数(ApplicationRunner 除了可以接收 CommandLineRunner 的参数之外,还可以接收 key/value形式的参数)。
使用 ApplicationRunner ,自定义类实现 ApplicationRunner 接口即可,组件注册以及组件优先级的配置都和 CommandLineRunner 一致,如下:
@Component
@Order(99)
public class MyApplicationRunner01 implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
String[] sourceArgs = args.getSourceArgs();//获取启动的所有参数
System.out.println("sourceArgs:" + Arrays.toString(sourceArgs));
List<String> nonOptionArgs = args.getNonOptionArgs();
System.out.println("nonOptionArgs:" + nonOptionArgs);
Set<String> optionNames = args.getOptionNames();
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>");
for (String optionName : optionNames) {
System.out.println(optionName + ":" + args.getOptionValues(optionName));
}
System.out.println(">>>>>>>>>>>>>>>MyApplicationRunner01结束>>>>>>>>>>>>>>>>");
}
}
@Component
@Order(98)
public class MyApplicationRunner02 implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
String[] sourceArgs = args.getSourceArgs();//获取启动的所有参数
System.out.println(“sourceArgs:” + Arrays.toString(sourceArgs));
List nonOptionArgs = args.getNonOptionArgs();
System.out.println(“nonOptionArgs:” + nonOptionArgs);
Set optionNames = args.getOptionNames();
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>");
for (String optionName : optionNames) {
System.out.println(optionName + “:” + args.getOptionValues(optionName));
}
System.out.println(">>>>>>>>>>>>>>>MyApplicationRunner02结束>>>>>>>>>>>>>>>>");
}
}
当项目启动时,这里的 run 方法就会被自动执行,关于 run 方法的参数 ApplicationArguments ,说如下几点:
- args.getNonOptionArgs();可以用来获取命令行中的无key参数(和CommandLineRunner一样)。
- args.getOptionNames();可以用来获取所有key/value形式的参数的key。
- args.getOptionValues(key));可以根据key获取key/value 形式的参数的value。
- args.getSourceArgs(); 则表示获取命令行中的所有参数。
加载xml配置
在资源目录下新建beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="org.javaboy.xml.SayHello" id="sayHello"/>
</beans>
写一个配置类
@Configuration
@ImportResource(locations = "classpath:beans.xml")
public class WebMvcConfig {
}
bean类
public class SayHello {
public String sayHello() {
return "hello xml";
}
}
测试
@RunWith(SpringRunner.class)
@SpringBootTest
public class XmlApplicationTests {
@Autowired
SayHello sayHello;
@Test
public void contextLoads() {
System.out.println(sayHello.sayHello());
}
}
这个功能很鸡肋一般不用
web基础组件
servlet
@WebServlet(urlPatterns = "/myservlet")
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("MyServlet");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}
过滤器
@WebFilter(urlPatterns = "/*")
public class MyFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("MyFilter");
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void destroy() {
}
}
监听器
@WebListener
public class MyRequestListener implements ServletRequestListener {
@Override
public void requestDestroyed(ServletRequestEvent sre) {
System.out.println("requestDestroyed");
}
@Override
public void requestInitialized(ServletRequestEvent sre) {
System.out.println("requestInitialized");
}
}
路径映射
简单的页面不需要渲染
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/cc").setViewName("cc");
//多个继续配置
// registry.addViewController("/gg").setViewName("gg);
}
在templates建一个html文件叫cc.html
参数类型转换
@ResponseBody
@GetMapping("/qq")
public String hello(Date birth) {
System.out.println(birth);
return birth.toString();
}
访问没有明显的报错但是会警告for value ‘2018-12-5’; nested exception is java.lang.IllegalArgumentException]
@Component
public class DateConverter implements Converter<String, Date> {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
@Override
public Date convert(String source) {
if (source != null && !"".equals(source)) {
try {
return sdf.parse(source);
} catch (ParseException e) {
e.printStackTrace();
}
}
return null;
}
}
这样访问就正常了