org.springframework.boot
spring-boot-starter-web
在springboot web依赖中加入了jackson-databind作为JSON处理器
public class Book {
private String name;
private String author;
@JsonIgnore
private Float price;
@JsonFormat(pattern = "yyyy-MM-dd")
private Date publicationDate;
}
@Controller
public class BookController {
@GetMapping("/book")
@ResponseBody
public Book book() {
Book book = new Book("bookName", "bookAuthor", 100f, new Date());
return book;
}
}
Gson是google的一个开源JSON解析框架。使用Gson,需要加入Gson依赖,并去除默认的jackson-databind
com.google.code.gson
gson
SpringBoot中默认提供了Gson自动转换,因此Gson的依赖添加后,就可以直接使用Gson。但是在Gson进行转换时,如果想对日期数据进行格式化。需要开发者自定义HttpMessageConverter自定义HttpMessageConverter
@Bean
GsonHttpMessageConverter gsonHttpMessageConverter() {
GsonHttpMessageConverter converter = new GsonHttpMessageConverter();
GsonBuilder gsonBuilder = new GsonBuilder();
//设置时间格式
gsonBuilder.setDateFormat("yyyy-MM-dd");
//设置gson解析时遇到protected修饰的字段被过滤掉
gsonBuilder.excludeFieldsWithModifiers(Modifier.PROTECTED);
Gson gson = gsonBuilder.create();
converter.setGson(gson);
return converter;
}
fastjson是阿里巴巴的一个开源JSON解析框架。是目前最快的JSON解析框架
SpringBoot中对于SpringMVC的自动化配置都在WebMvcAutoConfiguration类
SpringBoot默认会过滤所有的静态资源、而静态资源的位置一共有5个:
/
spring.mvc.static-path-pattern=/static/**
spring.web.resources.static-locations=classpath:/static/
public class MyWebMvcConfig implements WebMvcConfigurer{
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry){
registry.addResourceHandler("/static/**")
.addResourceLocations("classpath:/static/")
}
}
首先创建一个SpringBoot项目并添加spring-boot-starter-web依赖
在resources目录下的static目录创建一个upload.html
Title
创建文件上传接口
@PostMapping("/upload")
public String upload(MultipartFile uploadFile, HttpServletRequest req) {
String realPath = req.getSession().getServletContext().getRealPath("/uploadFile");
String format = sdf.format(new Date());
File folder = new File(realPath + format);
if (!folder.isDirectory()) {
folder.mkdirs();
}
String oldName = uploadFile.getOriginalFilename();
String newName = UUID.randomUUID().toString() + oldName.substring(oldName.lastIndexOf("."), oldName.length());
try {
uploadFile.transferTo(new File(folder, newName));
String filePath = req.getScheme() + "://" + req.getServerName() + ":" + req.getServerPort() + "/uploadFile/" + format + newName;
return filePath;
} catch (IOException e) {
e.printStackTrace();
}
return "上传失败";
}
@ControllerAdvice最常见的使用场景就是全局异常处理
@ControllerAdvice
public class CustomExceptionHandler {
@ExceptionHandler(MaxUploadSizeExceededException.class)
public void uploadException(MaxUploadSizeExceededException maxUploadSizeExceededException,
HttpServletResponse resp){
resp.setContentType("text/html;charset=utf-8");
PrintWriter writer = null;
try {
writer = resp.getWriter();
writer.write("超出文件大小限制");
writer.flush();
writer.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
当系统启动时,标记@ControllerAdvice就会被扫描到Spring容器中,然后在方法上添加@ExceptionHandler注解,其中定义的MaxUploadSizeExceededException.class表明该方法用来处理MaxUploadSizeExceededExceptioon类型的异常。
@ControllerAdvice是一个全局数据处理组件。可以在@ControllerAdvice中使用@ModelAttribute注解配置全局数据
@ControllerAdvice
public class GlobalConfig {
@ModelAttribute(value = "info")
public Map userInfo() {
HashMap map = new HashMap<>();
map.put("username", "lgz");
map.put("gender", "男");
return map;
}
}
@ControllerAdvice结合@InitBinder能实现请求参数预处理,即将表单中的数据绑定到实体类上时进行一些额外处理
例如有两个实体类Book和Author
public class Book {
private String name;
private String author;
//.....getter/setter
}
public class Author {
private String name;
private int age;
//......getter/setter
}
Controller
@RestController
public class InitBinderController {
@GetMapping("/book")
public String book(Book book, Author author) {
return book.toString() + ">>>" + author.toString();
}
}
这样在传递参数时,两个实体类中的name就会容易混淆。@ControllerAdvice结合@InitBinder可以顺利解决该问题
@RestController
public class InitBinderController {
@GetMapping("/book")
public String book(@ModelAttribute("a") Book book,
@ModelAttribute("b") Author author) {
return book.toString() + ">>>" + author.toString();
}
}
配置@ControllerAdvice
@InitBinder("a")
public void init(WebDataBinder binder) {
binder.setFieldDefaultPrefix("b.");
}
@InitBinder("b")
public void init2(WebDataBinder binder) {
binder.setFieldDefaultPrefix("a.");
}
然后在浏览器中访问:http://localhost:8080/book?b.name=bname&b.author=bauthor&a.name=aname&a.age=aAge即可成功地区分出name属性
@ControllerAdvice可以处理应用级别的异常,有一些容器级别的错误就处理不了。
在SpringBoot中,默认情况下,404、500等会有统一的处理页面。
SpringBoot在返回错误信息时不一定返回HTML页面,而是根据实际情况返回HTML页面或者一段JSON
SpringBoot中的错误默认是由BasicErrorContoller类来处理的
@RequestMapping(produces = MediaType.TEXT_HTML_VALUE)
public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
HttpStatus status = getStatus(request);
Map model = Collections
.unmodifiableMap(getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.TEXT_HTML)));
response.setStatus(status.value());
ModelAndView modelAndView = resolveErrorView(request, response, status, model);
return (modelAndView != null) ? modelAndView : new ModelAndView("error", model);
}
@RequestMapping
public ResponseEntity
errorHtml方法用来返回错误HTML页面,error用来返回错误JSON
DefaultErrorViewResolver是SpringBoot中默认的错误信息视图解析器,SpringBooot默认是在error目录下查找4xx、5xx的文件作为错误视图,找不到时会回到errorHtml中,然后使用error作为默认的错误页面视图名,如果error的视图也找不到,用户就会看到默认的错误提示页面
如果想自定义错误页面,只需要提供4xx、5xx的页面即可。
如果不需要向用户展示详细的错误信息,可以把错误信息定义成静态页面,直接在resources/static目录下创建error目录,然后在error目录中创建错误展示页面,错误展示页面的命名规则有:
动态页面
如果采用视图模板技术,先添加依赖,然后在templates目录下创建error目录,然后创建错误展示页
CORS:是一种跨域资源共享技术标准,目的就是为了解决前端的跨域请求。CORS支持多种HTTP请求
定义一个Controller
@RestController
@RequestMapping("/book")
public class BookController {
@PostMapping("/")
public String addBook(String bookName) {
return "receive" + bookName;
}
@DeleteMapping("{id}")
public String delBook(@PathVariable("id") Long id) {
return String.valueOf("id");
}
}
跨域有两个配置地方,
@RestController
@RequestMapping("/book")
public class BookController {
@PostMapping("/")
@CrossOrigin(value = "http://localhost:8081",maxAge = 1800,allowedHeaders = "*")
public String addBook(String bookName) {
return "receive" + bookName;
}
@DeleteMapping("{id}")
@CrossOrigin(value = "http://localhost:8081",maxAge = 1800,allowedHeaders = "*")
public String delBook(@PathVariable("id") Long id) {
return String.valueOf("id");
}
}
@Configuration
public class MyWebMvcConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/book/**")
.allowedHeaders("*")
.allowedMethods("*")
.maxAge(1800)
.allowedOrigins("http://localhost:8081");
}
}
SpringBoot的配置类需要添加@Configuration注解,@ComponentScan注解会扫描所有的Spring组件。也包括@Configuration
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandler>>>>");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandler>>>>");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion>>>>");
}
}
拦截器中的方法将按照
preHandle->Controller->postHandle->afterCompletion
@Configuration
public class MyWebMvcConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/book/**")
.allowedHeaders("*")
.allowedMethods("*")
.maxAge(1800)
.allowedOrigins("http://localhost:8081");
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/hello");
}
}
有一些特殊的任务需要在系统启动时执行,配置文件加载,数据库初始化等操作。SpringBoot对此提供了两种解决方案 CommandLineRunner 和 ApplicationRunner
SpringBoot项目在启动时会遍历所有CommandLineRunner的实现类并调用其中的run方法,如果有多个实现类,那么可以使用@Order注解对这些实现类的调用顺序进行排序
@Component
@Order(1)
public class MyCommandLineRunner implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("first runner"+ Arrays.toString(args));
}
}
@Component
@Order(2)
public class MyCommandLineRunner2 implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("second runner"+ Arrays.toString(args));
}
}
ApplicationRunner和CommandLineRunner基本一致,区别主要体现在run方法的参数上
在使用页面模板后,用户需要通过Controller才能访问页面,一些页面需要在控制器中加载数据,然后渲染,才能显示出来。还有一些页面在控制器中不需要加载数据,只是完成简单的跳转。对于这种页面,可以直接配置路径映射,提高访问速度
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login").setViewName("login");
registry.addViewController("/index").setViewName("index");
}
SpringBoot在Spring的基础上对AOP的配置提供了自动化配置解决方案:spring-boot-starter-aop,使开发者能够更加便捷地在SpringBoot项目中使用AOP
org.springframework.boot
spring-boot-starter-aop
@Service
public class UserService {
public String getUserById(Integer id) {
System.out.println("getUserById = " + id);
return "user";
}
public void deleteUserById(Integer id) {
System.out.println("deleteUserById"+ id);
}
}
@Component
@Aspect
public class LogAspect {
@Pointcut("execution(* com.probuing.springbootcros.service.*.* (..))")
public void pc1() {
}
@Before(value = "pc1()")
public void before(JoinPoint jp) {
String name = jp.getSignature().getName();
System.out.println(name + "方法开始执行");
}
@After(value = "pc1()")
public void after(JoinPoint jp) {
String name = jp.getSignature().getName();
System.out.println(name + "方法执行结束");
}
@AfterReturning(value = "pc1()", returning = "result")
public void afterRunning(JoinPoint jp, Object result) {
String name = jp.getSignature().getName();
System.out.println(name + "方法返回值为" + result);
}
@AfterThrowing(value = "pc1()", throwing = "e")
public void afterThrowing(JoinPoint jp, Exception e) {
String name = jp.getSignature().getName();
System.out.println(name + "方法异常了" + e.getMessage());
}
@Around(value = "pc1()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
return pjp.proceed();
}
}
目标方法进入环绕通知后,通过调用ProceedingJoinPoint对象的proceed方法使目标方法继续执行,开发者可以在此修改目标方法的执行参数、返回值等,并且可以在此处理目标方法的异常SpringBoot项目在启动后,首先会去静态资源路径下查找index.html作为首页文件,若查找不到,则会去查找动态的index文件作为首页
如果使用静态的index.html作为项目首页,那么只需要在resources/static目录下创建index.html。如果使用动态页面作为项目首页则需要在resources/templates目录下创建index.html,然后在Controller中返回逻辑视图名。
favicon.ico是浏览器选项卡左上角的图标,可以放在静态资源路径下或者类的路径下,静态资源路径下的favicon.ico优先级高于favicon.co
将图标文件复制到/resources/static 目录下
喜欢的朋友记得点赞、收藏、关注哦!!!