栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

SpringBoot2.x笔记——整合Web开发

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

SpringBoot2.x笔记——整合Web开发

MVC框架

SpringMVC是一种基于Java,实现了Web MVC设计模式,请求驱动类型的轻量级Web框架,即使用了MVC架构模式的思想,将Web层进行职责解耦。基于请求驱动指的就是使用请求-响应模型,框架的目的就是帮助我们简化开发,SpringMVC也是要简化我们日常Web开发。

引入依赖

SpringBoot 集成SpringMVC框架并实现自动配置,只需要在pom中添加以下依赖即可,不需要其他任何配置:


    org.springframework.boot
    spring-boot-starter-web

JSON配置

JSON是目前主流的前后端数据传输方式,SpringMVC中使用消息转换器HttpMessageConverter对JSON 的转换提供了很好的支持。添加上述的依赖后,我们的项目就可以返回一段JSON了。

默认使用
@Data
public class Table {
    //主键
    private Integer id;
    //名称
    private String name;
    //时间
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date date;
}

@RestController
public class TableController {
    @Resource
    private TableDao tableDao;

    
    @PostMapping("/queryAll")
    public List queryAll() {
        return tableDao.queryAll(new Table());
    }
}

@SpringBootTest
public class TableControllerTest {
    @Resource
    private WebApplicationContext wac;
    private MockMvc mockMvc;

    @BeforeEach
    public void init(){
        //初始化MockMvc对象
        mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
    }

    @Test
    public void queryAll() throws Exception {
        String str = mockMvc.perform(MockMvcRequestBuilders.post("/queryAll"))
                .andExpect(status().isOk())
                .andReturn().getResponse().getContentAsString(StandardCharsets.UTF_8);
        System.out.println(str);
    }
}


这是SpringBoot自带的处理方式,通过Spring中默认提供的MappingJackson2HttpMessageConvert类来实现的。如果采用这种方式,那么对于字段忽略、日期格式化等常见需求都可以通过注解来解决。

自定义转换器

常见的JSON处理器除了jackson-databind外,还有 Gson、fastjson等。

使用Gson
  1. 添加依赖

    org.springframework.boot
    spring-boot-starter-web
        
            
                com.fasterxml.jackson.core
                jackson-databind
            
        


    com.google.code.gson
    gson

  1. 由于SpringBoot中默认提供了Gson的配置类GsonHttpMessageConvertersConfiguration,因此Gson的依赖添加成功后,可以像使用jackson-databind那样直接使用。但是如果想对日期数据进行格式化,那么还需要自定义HttpMessageConverter,代码如下:
@Configuration
public class WebBeanConfig {
    
    @Bean
    GsonHttpMessageConverter gsonHttpMessageConverter() {
        GsonHttpMessageConverter converter = new GsonHttpMessageConverter();
        GsonBuilder gsonBuilder = new GsonBuilder();
        gsonBuilder.setDateFormat("yyyy-MM-dd HH:mm:ss");
        gsonBuilder.excludeFieldsWithModifiers(Modifier.PROTECTED);
        converter.setGson(gsonBuilder.create());
        return converter;
    }
}

使用fastjson

fastjson是阿里巴巴的一个开源JSON框架是目前JSON解析速度最快的开源框架,该框架也可以集成到 Spring Boot 中。不同于Gson, fastjson承完成之后并不能立马使用, 需要提供相应的httpMessageConverter后才能使用,配置如下:

  1. 添加依赖

    org.springframework.boot
    spring-boot-starter-web
        
            
                com.fasterxml.jackson.core
                jackson-databind
            
        


    com.alibaba
    fastjson
    1.2.70

  1. 对于FastJsonHttpMessageConverter的配置,有一个WebMvcAutoConfiguration类提供了对
    SpringMVC最基本的配置,如果某一项自动化配置不满足开发需求,可以针对该项自定义配置,只需要实现WebMvcConfigurer对应的接口即可,配置如下:
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    
    @Override
    public void configureMessageConverters(List> converters) {
        //创建fastJson消息转换器
        FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
        //新版本(当前版本1.2.70)需要配置支持的MediaType, 不然就会报错
        List supportedMediaTypes = new ArrayList<>();
        supportedMediaTypes.add(MediaType.APPLICATION_JSON);
        supportedMediaTypes.add(MediaType.APPLICATION_ATOM_XML);
        supportedMediaTypes.add(MediaType.APPLICATION_FORM_URLENCODED);
        supportedMediaTypes.add(MediaType.APPLICATION_OCTET_STREAM);
        supportedMediaTypes.add(MediaType.APPLICATION_PDF);
        supportedMediaTypes.add(MediaType.APPLICATION_RSS_XML);
        supportedMediaTypes.add(MediaType.APPLICATION_XHTML_XML);
        supportedMediaTypes.add(MediaType.APPLICATION_XML);
        supportedMediaTypes.add(MediaType.IMAGE_GIF);
        supportedMediaTypes.add(MediaType.IMAGE_JPEG);
        supportedMediaTypes.add(MediaType.IMAGE_PNG);
        supportedMediaTypes.add(MediaType.TEXT_EVENT_STREAM);
        supportedMediaTypes.add(MediaType.TEXT_HTML);
        supportedMediaTypes.add(MediaType.TEXT_MARKDOWN);
        supportedMediaTypes.add(MediaType.TEXT_PLAIN);
        supportedMediaTypes.add(MediaType.TEXT_XML);
        fastConverter.setSupportedMediaTypes(supportedMediaTypes);
        FastJsonConfig config = new FastJsonConfig();
        config.setDateFormat("yyyy-MM-dd HH:mm:ss");
        //格式化的规则
        config.setSerializerFeatures(
                SerializerFeature.WriteDateUseDateFormat,
                SerializerFeature.WriteNullListAsEmpty,
                SerializerFeature.WriteMapNullValue
        );
        fastConverter.setFastJsonConfig(config);
        converters.add(fastConverter);
    }
}

静态资源访问

在SpringMVC中,对于静态资源都需要手动配置静态资源过滤。SpringBoot中对此也提供自动化配置,可以简化静态资源过滤配置。

默认配置

在WebMvcAutoConfiguration类中有一个静态内部类WebMvcAutoConfigurationAdapter实现了
WebMvcConfigurer接口。WebMvcConfigurer接口中有一个个方法addRsourceHandlers,
是用来配置静态资源过滤的。方法在WebMvcAutoConfigurationAdapter中得到了实现。

其中默认添加了下面几个文件路径:

在registration.addResourceLocations(resource)中添加了"/“路径

综上可以得到,SpringBoot过滤所有的静态资源,而静态资源的位置一共有5个,分别是"classpath:/META-INF/resources”、“classpath: /resources/”、“classpath: /static/”、“classpath :/public/”、“/”。也就是可以将静态资源放到这5个位置中的任意一个,其中按照定义的顺序优先级依次降低。一般情况下SpringBoot项目不需要webapp目录,所以第5个"/"可以暂不考虑。

自定义配置

如果默认静态资源过滤策略不能满足需求 ,也可以自定义静态资源过滤策略。

  1. 在配置文件中配置
spring:
  mvc:
    static-path-pattern: /static
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/static
    @Bean
    public WebHandlerExceptionResolver webHandlerExceptionResolver() {
        return new WebHandlerExceptionResolver();
    }
}

非Controller抛出的异常

上述两种方法一般用来处理应用级别的异常,有一些不是controller抛出的异常就处理不了,例如Filter中抛出异常等。因此,SpringBoot提供BasicErrorControll作为默认的ErrorController,我们如果需要更灵活地对Error视图和数据进行处理,那么只需要提供自己的ErrorController即可。

@RestController
public class WebErrorController extends BasicErrorController {

    public WebErrorController(ErrorAttributes errorAttributes) {
        super(errorAttributes, new ErrorProperties());
    }

    @Override
    public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
        ModelAndView mv = new ModelAndView(new MappingJackson2JsonView());
        Map body = getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.ALL));
        WebResponse webResponse = new WebResponse();
        webResponse.setCode(-1);
        webResponse.setType("error");
        webResponse.setMessage((String) body.get("message"));
        mv.addAllObjects(webResponse.toMap());
        mv.setStatus(getStatus(request));
        return mv;
    }

    @Override
    public ResponseEntity> error(HttpServletRequest request) {
        Map body = getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.ALL));
        WebResponse webResponse = new WebResponse();
        webResponse.setCode(-1);
        webResponse.setType("error");
        webResponse.setMessage((String) body.get("message"));
        return new ResponseEntity>(webResponse.toMap(), getStatus(request));
    }

    @Override
    protected ErrorAttributeOptions getErrorAttributeOptions(HttpServletRequest request, MediaType mediaType) {
        ErrorAttributeOptions options = ErrorAttributeOptions.of(ErrorAttributeOptions.Include.EXCEPTION,
                ErrorAttributeOptions.Include.STACK_TRACE, ErrorAttributeOptions.Include.MESSAGE,
                ErrorAttributeOptions.Include.BINDING_ERRORS);
        if (getErrorProperties().isIncludeException()) {
            options = options.including(ErrorAttributeOptions.Include.EXCEPTION);
        }
        if (isIncludeStackTrace(request, mediaType)) {
            options = options.including(ErrorAttributeOptions.Include.STACK_TRACE);
        }
        if (isIncludeMessage(request, mediaType)) {
            options = options.including(ErrorAttributeOptions.Include.MESSAGE);
        }
        if (isIncludeBindingErrors(request, mediaType)) {
            options = options.including(ErrorAttributeOptions.Include.BINDING_ERRORS);
        }
        return options;
    }
}

@WebFilter("
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/web
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new InterceptorTest())
                .addPathPatterns("/**")
                .excludePathPatterns("/query");
    }
}

拦截器中的方法将按 preHandle→Controller→postHandle→afterCompletion的顺序执行。注意,只有 preHandle方法返回true时后面的方法才会执行。当拦截器链内存在多个拦截器时,postHandler在拦截器链内的所有拦截器返回成功时才会调用,而afterCompletion只有preHandle返回true才调用,但若拦截器链内的第一个拦截器preHandle方法返回false后面的方法都不会执行。

启动系统任务

有一些特殊的任务需要在系统启动时执行,例如配置文件加载、数据库初始化等操作。如果没有使用SpringBoot,这些问题可以在Listener中解决。SpringBoot对此提供了两种解决方案:CommandLineRunner和ApplicationRunner。CommandLineRunner和ApplicationRunner基本一致
差别主要体现在参数上。

CommandlineRunner
@Component
@Order(1)
public class WebCommandlineRunner1 implements CommandLineRunner {

    @Override
    public void run(String... args) throws Exception {
        System.out.println("我是Runner1,参数为" + Arrays.toString(args));
    }
}

@Component
@Order(1)
public class WebCommandlineRunner2 implements CommandLineRunner {

    @Override
    public void run(String... args) throws Exception {
        System.out.println("我是Runner2,参数为" + Arrays.toString(args));
    }
}
  • Order:用来描述CommandLineRunner的执行顺序,数字越小越先执行
  • run方法:是调用的核心逻辑,参数是系统启动时传入的参数,即入口类main方法的参数
ApplicationRunner
@Component
@Order(1)
public class WebApplicationRunner1 implements ApplicationRunner {

    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("我是WebApplicationRunner1,参数为" + args.getNonOptionArgs());
    }
}

@Component
@Order(2)
public class WebApplicationRunner2 implements ApplicationRunner {

    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("我是WebApplicationRunner2,参数为" + args.getNonOptionArgs());
    }
}
  • Order:执行顺序 ,数字越小越优先执行
  • 这里run方法的参数是ApplicationArguments对象,如果想从ApplicationArguments对象中获取入口类中 main方法接收的参数,调 ApplicationArguments中的getNonOptionArgs方法即可。ApplicationArguments中的getOptionNam方法用来获取项目启动命令行中参数key,getOptionNames方法获取到的是name,getOptionValues则是获取相应的value。
Servlet、Filter、Listener配置
@WebServlet("/testServlet")
public class TestServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("Servlet-------测试servlet的使用");
    }
}

@WebFilter("/*")
public class TestFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("Filterr-------测试Filter的使用");
//        throw new RuntimeException("我是Filter抛出的异常,测试BasicErrorController的作用");
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {

    }
}

@WebListener
public class TestListener implements ServletRequestListener {
    @Override
    public void requestDestroyed(ServletRequestEvent sre) {
        System.out.println("Listener-------requestDestroyed");
    }

    @Override
    public void requestInitialized(ServletRequestEvent sre) {
        System.out.println("Listener-------requestInitialized");
    }
}

在项目入口类上添加@ServletComponentScan注解,实现对 Servlet、Filter以及Listener的扫描

REST

REST(Representational State Transfer)是Web软件架构风格,它是一种风格,而不是标准,匹配或兼容这种架构风格的网络服务称为REST服务。REST服务简洁并且有层次,REST通常基于 HTTP、URI和XML以及HTML这些现有的广泛流行的协议和标准。在 REST 中,资源是URI 来指定的,对资源的增删改查操作可以通过HTTP协议提供的GET、POST、PUT、DELETE等方法实现。使用REST可以更高效地利用缓存来提高响应速度,同时REST中的通信会话状态由客户端来维护,这可以让不同的服务器 处理一系列请求中的不同请求,进而提高服务器的扩展性。前后端分离项目中,一个设计良好的Web软件架构必然要满足REST风格。SpringMVC框架中,开发者可以通过@RestController注解开发一个RESTful 服务。

标识资源

将资源名称放到 也中,如果资源有层级关系,则放入层级关系:

http://localhost:8080/web/api/table
确定HTTP Method

在REST中,HTTP Method常常对应以下含义:

  • POST:代表增加资源;
  • PUT:代表更改资源,客户端提供需完整的资源属性;
  • GET:代表查询资源;
  • PATCH:更新资源,客户端提供仅需要更改的资源属性;
  • DELETE:通常用于删除资源;
  • HEAD:类似GET,但仅仅只有 HTTP 头信息,头信息包含了需要查找的信息;
  • OPTIONS:用于获取URI所支持的方法,响应信息会在HTTP头中包含一个个名为Allow
    的头,值是所支持的方法,如GET、POST;
确定HTTP Status

服务器向客户端返回HTPP Status以表示操作是否成功,常用的如下:

  • 200:0K,用户请求成功,如查询数据成功返回;
  • 400:错误的的请求,URI匹配上SpringBoot中的Controller,但方法参
    数匹配错误,就会抛出错误;
  • 404:NOT Found,用户发出的请求针对的资源不存在;
  • 405:用来访问本页面的HTTP Method不被允许,比如通过HTTP GET方式访问了一个@PostMapping Controller 方法;
  • 406:表示无法使用请求的内容特性来响应请求的资源,比如在SpringBoot中,请求后缀以html结尾,但同时请求的HTTP头中又包含了Accept:application/json;
  • 500:服务器内部错误,无法完成请求,通常是 Controller抛出的异常。
SpringBoot集成REST 依赖

    org.springframework.boot
    spring-boot-starter-data-rest



    org.springframework.boot
    spring-boot-starter-data-jpa


  
    mysql
    mysql-connector-java
    runtime



    org.projectlombok
    lombok

代码实现
server:
  servlet:
    context-path: /rest
  port: 8080

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver
  jpa:
    hibernate:
      ddl-auto: none
    database: mysql
    show-sql: true
  mvc:
    hiddenmethod:
      filter:
        enabled: true

@Data
@Entity
public class Student {
    //主键
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    //名称
    private String name;
    //时间
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date time;
}

@RepositoryRestResource
public interface StudentRepository extends JpaRepository {

}

自定义路径
@RepositoryRestResource(path = "teachers", collectionResourceRel = "t", itemResourceRel = "teacher")
public interface StudentRepository extends JpaRepository {

}

@RepositoryRestResource注解:

  • path:表示将所有请求路径中的students都修改为teachers;
  • collectionResourceRel:表示将返回的JSON集合中students集合的key修改为t
  • itemResourceRel:表示将返回JSON集合中的单个student的key修改为teacher

项目地址git@github.com:fengfangithub/study-springboot.git

转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号