Spring Boot - 集成Web开发(自定义Servlet、Filter、Interceptor)

Spring Boot - 集成Web开发

 使用Spring Boot进行web开发十分简单,其中包括常用的接口json返回、servlet、filters、interceptor、log等,在这之前我们已经了解了Spring Boot配置文件和基本的使用,接下来我们就来看一下Spring Boot是如何集成Web开发的。

1.Json接口开发

 我们在没有使用Spring Boot之前首先需要引入jackjson对应的依赖,配置spring扫描,然后在对应Controller和接口上加上@Controller以及@ResponseBody注解,这是我们习惯开发接口的方式。现在利用Spring Boot去开发接口,只需保证接口类处于入口类扫描范围内,Controller加上@RestController注解就可以提供一个接口服务。

application.properties
server.port=8080
server.servlet.context-path=/springboot-basic
User.java
package com.springboot.repository.entity;

/**
 * @author hzk
 * @date 2018/12/19
 */
public class User {

    private Integer id;

    private String name;

    public User(Integer id, String name) {
        this.id = id;
        this.name = name;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

UserController .java
package com.springboot.controller;

import com.springboot.repository.entity.User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author hzk
 * @date 2018/12/19
 */
@RestController
public class UserController {

    @GetMapping(value = "/user/{id}/{name}")
    public User user(@PathVariable(name = "id") Integer id, @PathVariable("name") String name){
        return new User(id,name);
    }
}


SpringbootBasicApplication.java
package com.springboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;

/**
 * 所需扫描的类必须写在启动类同级或者子级目录下
 * @author hzk
 * @date 2018/12/18
 */
@SpringBootApplication
public class SpringbootBasicApplication {

	public static void main(String[] args) {
		SpringApplication.run(SpringbootBasicApplication.class, args);
	}

}

 简单几步就完成了一个Json接口开发,请求http://localhost:8080/springboot-basic/user/88/jack可以看到和我们预期效果一致。

运行结果
{
	id: 88,
	name: "jack"
}

2.集成使用Jsp

 通常有些项目采用jsp作为视图开发,在没有使用Spring Boot之前我们需要在spring的xml配置文件中配置对应的视图属性,这里我们也需要配置spring mvc的视图属性,不过通过简单的配置就能基本实现jsp的集成使用。

application.properties
#激活加载application-x.properties文件 此时取application-qa.properties 该命名格式约定俗成
#若application.properties主配置文件和激活配置文件中存在相同配置属性,则优先取激活配置文件中属性,例:主配置文件和激活配置文件中都配置了启动端口号,则使用激活配置文件中端口号
spring.profiles.active=qa

#spring.http.encoding.charset=UTF-8
#spring.http.encoding.force=true
#spring.http.encoding.enabled=true

#配置mvc视图
spring.mvc.view.prefix=/
spring.mvc.view.suffix=.jsp
ViewController.java
package com.springboot.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * @author hzk
 * @date 2018/12/19
 */
@Controller
public class ViewController {

    @RequestMapping(value = "/index")
    public String index(Model model){
        model.addAttribute("msg","spring boot集成jsp");
        return "index";
    }
}

index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
         pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Insert title here</title>
</head>
<body>
${msg}
</body>
</html>

 请求http://localhost:8080/springboot-basic/index就能跳转到我们的index页面,和没有使用Spring Boot时效果一样。

3.自定义Servlet

 在我们使用Spring框架之后很少再去自己编写Servlet服务,但是这里我们也介绍一下在Spring Boot下如何去编写实现一个Servlet服务,这里主要有两种实现方式,首先我们看下目录结构。

- java
	- com
		- springboot
			- config
				- ServletConfig.java
			- servlet
				- MyServlet.java
				- MyServlet2.java
			- SpringbootApplication.java
- resources
3.1 使用Servlet3注解实现

 首先我们要编写一个Servlet服务,并且添加上@WebServlet注解。

MyServlet.java
package com.springboot.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 第一种方式@WebServlet注解加上主程序@ServletComponentScan注解扫描
 * @author hzk
 * @date 2018/12/26
 */
@WebServlet(urlPatterns = "/myServlet")
public class MyServlet extends HttpServlet{

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().print("my servlet doGet ..");
        resp.getWriter().flush();
        resp.getWriter().close();
    }

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

 编写好了Servlet服务之后,只需在入口类上配置Servlet扫描@ServletComponentScan,访问http://localhost:8080/springboot-basic/myServlet即可。

SpringbootBasicApplication.java
package com.springboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;

/**
 * 所需扫描的类必须写在启动类同级或者子级目录下
 * @author hzk
 * @date 2018/12/18
 */
@SpringBootApplication
@ServletComponentScan(basePackages = "com.springboot.servlet")
public class SpringbootBasicApplication {

	public static void main(String[] args) {
		SpringApplication.run(SpringbootBasicApplication.class, args);
	}

}
3.2 编写Servlet配置类

 同样我们要先编写一个Servlet服务。

MyServlet2.java
package com.springboot.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 第二种方式添加ServletConfig自定义配置文件 使用springboot提供的方式手动注册servlet
 * @author hzk
 * @date 2018/12/26
 */
public class MyServlet2 extends HttpServlet{

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().print("my servlet2 doGet..");
        resp.getWriter().flush();
        resp.getWriter().close();
    }

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

 编写好Servlet服务后,在config包下新建一个ServletConfig配置类用于注册Servlet,需加上@Configuration注解才有效。

ServletConfig.java
package com.springboot.config;

import com.springboot.filter.MyFilter2;
import com.springboot.servlet.MyServlet2;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.CharacterEncodingFilter;

import javax.servlet.Filter;

/**
 * springboot不使用xml文件,@Configuration可以替代xml配置文件
 * 该方式类似于添加xml文件配置
 * @author hzk
 * @date 2018/12/26
 */
@Configuration
public class ServletConfig {

    @Bean
    public ServletRegistrationBean<MyServlet2> myServletRegistrationBean(){
        return new ServletRegistrationBean<>(new MyServlet2(), "/myServlet2");
    }
}

 配置完之后启动,访问http://localhost:8080/springboot-basic/myServlet2即可。

4.自定义Filter过滤器

 我们在项目中经常会使用filter去做一些公共处理,比如跨域请求、排除有XSS威胁的字符、权限验证等等。我们会根据业务需求自定义Filter,和Servlet的实现方式一样有两种,我们看一下目录结构。

- java
	- com
		- springboot
			- config
				- ServletConfig.java
			- filter
				- MyFilter.java
				- MyFilter2.java
			- SpringbootApplication.java
- resources
4.1 使用@WebFilter注解实现

 首先我们要编写一个自定义Filter类去实现Filter接口重写其中doFilter方法,然后使用@WebFilter注解配置过滤器过滤范围

MyFilter.java
package com.springboot.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

/**
 * 第一种方式@WebFilter注解加上主程序@ServletComponentScan注解扫描
 * @author hzk
 * @date 2018/12/26
 */
@WebFilter(urlPatterns = "/*")
public class MyFilter implements Filter{

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("MyFilter into...");
        filterChain.doFilter(servletRequest,servletResponse);
    }

    @Override
    public void destroy() {

    }
}

 通过这种方式编写的自定义Filter过滤器,需要在入口类上配置Servlet扫描@ServletComponentScan,和之前Servlet第一种实现一样,若配置多个可以用逗号分隔。

SpringbootBasicApplication.java
package com.springboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;

/**
 * 所需扫描的类必须写在启动类同级或者子级目录下
 * @author hzk
 * @date 2018/12/18
 */
@SpringBootApplication
@ServletComponentScan(basePackages = {"com.springboot.servlet","com.springboot.filter"})
public class SpringbootBasicApplication {

	public static void main(String[] args) {
		SpringApplication.run(SpringbootBasicApplication.class, args);
	}

}
4.2 编写Filter配置类

 同第一种一样我们要编写一个自定义Filter,区别是这里不需要加上@WebServlet注解。

MyFilter2.java
package com.springboot.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

/**
 * 第二种方式添加ServletConfig自定义配置文件 使用springboot提供的方式手动注册filter
 * @author hzk
 * @date 2018/12/26
 */
public class MyFilter2 implements Filter{

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("MyFilter2 into...");
        filterChain.doFilter(servletRequest,servletResponse);
    }

    @Override
    public void destroy() {

    }
}

 编写好自定义Filter过滤器后,编写一个配置类,我们使用开始的ServletConfig,通过实例化FilterRegistrationBean便可以将MyFilter2这个过滤器注册到Spring容器中加入到过滤器链中。

ServletConfig.java
package com.springboot.config;

import com.springboot.filter.MyFilter2;
import com.springboot.servlet.MyServlet2;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.CharacterEncodingFilter;

import javax.servlet.Filter;

/**
 * springboot不使用xml文件,@Configuration可以替代xml配置文件
 * 该方式类似于添加xml文件配置
 * @author hzk
 * @date 2018/12/26
 */
@Configuration
public class ServletConfig {

    @Bean
    public ServletRegistrationBean<MyServlet2> myServletRegistrationBean(){
        return new ServletRegistrationBean<>(new MyServlet2(), "/myServlet2");
    }

    @Bean
    public FilterRegistrationBean<MyFilter2> myFilterRegistration(){
        FilterRegistrationBean<MyFilter2> filterRegistrationBean = new FilterRegistrationBean<>(new MyFilter2());
        String[] urlPatterns = {
                "/*"
        };
        filterRegistrationBean.addUrlPatterns(urlPatterns);
        return filterRegistrationBean;
    }

    /**
     * 等同web.xml配置CharacterEncodingFilter
     * 注意:若想使用自定义编码过滤器,则spring.http.encoding.enabled=false才可生效
     * @return
     */
   /* @Bean
    public FilterRegistrationBean<CharacterEncodingFilter> filterRegistrationBean(){
        FilterRegistrationBean<CharacterEncodingFilter> filterFilterRegistrationBean = new FilterRegistrationBean<CharacterEncodingFilter>();
        CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
        characterEncodingFilter.setEncoding("UTF-8");
        characterEncodingFilter.setForceEncoding(true);
        filterFilterRegistrationBean.setFilter(characterEncodingFilter);
        filterFilterRegistrationBean.addUrlPatterns("*//*");
        return filterFilterRegistrationBean;
    }*/

}

5.自定义Interceptor拦截器

 我们知道Filter和Interceptor表面上比较有很多相似之处,但是也有十分大的差异化。比如Filter依赖Servlet容器而Interceptor则不需要、Filter基于函数回调而Interceptor基于反射、Filter不可以使用Spring容器资源而Interceptor可以等,具体细节差异各位可以查询书籍或者网上的资料。这里可以参考这几篇博客内容,写的通俗易懂也比较详细。
过滤器(Filter)和拦截器(Interceptor)的区别-xiaodanjava
过滤器(Filter)和拦截器(Interceptor)的区别-军子
SpringMVC的拦截器(Interceptor)和过滤器(Filter)的区别与联系
 在了解过Interceptor拦截器后我们来看下Spring Boot中我们应该如何去实现,这里照例给出目录结构。

- java
	- com
		- springboot
			- config
				- WebConfig.java
			- interceptor
				- AuthInterceptor.java
			- SpringbootApplication.java
- resources

 我们需要先编写一个自定义interceptor去实现HandlerInterceptor重写其中的方法,这里我们定义一个AuthInterceptor权限验证拦截器。

AuthInterceptor.java
package com.springboot.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 权限验证拦截器
 * @author hzk
 * @date 2018/12/26
 */
public class AuthInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("AuthInterceptor into...");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}

 要使这个拦截器生效,我们需要有一个自定义配置类去注册拦截器,该类需要继承WebMvcConfigurationSupport 实现addInterceptors方法将自定义拦截器注册Web容器中。

WebConfig.java
package com.springboot.config;

import com.springboot.interceptor.AuthInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

/**
 * @author hzk
 * @date 2018/12/26
 */
@Configuration
public class WebConfig extends WebMvcConfigurationSupport {

    @Override
    protected void addInterceptors(InterceptorRegistry registry) {

        //需要拦截的路径
        String[] pathPatterns = {
                "/api/**"
        };
        //需要放行的路径
        String[] excludePathPatterns = {
                "/api/config"
        };

        registry.addInterceptor(new AuthInterceptor()).addPathPatterns(pathPatterns).excludePathPatterns(excludePathPatterns);
    }
}

6.RESTFull实现

 首先在实现RESTFull之前,我们需要弄明白什么是RESTFull?

  1. RESTFULL是一种互联网软件架构设计风格,并不是标准,只是提出了一组客户端和服务器交互时的架构理念和设计原则,基于该理念和原则设计的接口可以更简洁,更有层次
  2. 如果一个架构符合REST原则,就称之为RESTFull架构
    比如我们访问一个http接口:http://localhost:8080/api/user?id=88&name=jack
    采用RESTFull风格则http地址为:http://localhost:8080/api/user/88/jack

 我们用Spring Boot实现RESTFull风格接口时,主要有一个核心的注解@PathVariable,这个注解可以帮我们获取url中的数据并且设定接口风格,例如我们下面这个接口就简单实现了RESTFull风格接口的开发。

UserController.java
package com.springboot.controller;

import com.springboot.repository.entity.User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author hzk
 * @date 2018/12/19
 */
@RestController
public class UserController {

    @GetMapping(value = "/user/{id}/{name}")
    public User user(@PathVariable(name = "id") Integer id, @PathVariable("name") String name){
        return new User(id,name);
    }
}

 这个接口的请求地址我们用http://localhost:8080/user/88/jack就可以请求成功并且返回正确的数据,相比我们以前的请求方式更加简便,我们还可以通过@PostMapping@PutMapping@DeleteMapping注解控制接口的请求方式,这些知识RESTFull风格的冰山一角,更多细节的东西需要大家自己根据所需去了解。

7.热部署插件

 在我们实际开发中,我们每次修改了代码逻辑功能或者页面调整都需要去重启我们的应用,从而无形中降低了我们开发的效率,但是Spring Boot给我们提供了一个热部署的插件,加入了这个插件之后当我们代码进行了修改之后无需重新启动就会自动加载新的内容。加入热部署插件很简单,只需要我们加入一个依赖,但是需要注意的是实际使用中可能会出现一些问题,比如有时候无法生效,仍然需要手动重启服务。

pom.xml
<!-- springboot 热部署-->
<!--实际开发中,我们修改代码逻辑需要重启应用,无形降低了开发效率。我们可以通过热部署插件,服务会自动加载新的内容,大大提高了开发效率,
实际使用中可能会出现一些问题,比如有时候无法生效,仍然需要手动重启服务。-->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-devtools</artifactId>
	<optional>true</optional>
</dependency>

8.SpringBoot默认日志LOGO关闭

 当我们每次启动Spring Boot项目的时候,我们都会看到日志中出现下面这个logo。

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.1.1.RELEASE)

 虽然这个logo的可有可无对项目都没有任何影响,但是可能考虑到有些同学强迫症不想要看到这个logo,Spring Boot的开发团队也是考虑地十分细心,给我们提供了方法可以将他关闭,只需要在入口类启动项目的时候稍作修改就可以关闭这个logo在日志中输出。

 public static void main( String[] args )
    {
        SpringApplication springApplication = new SpringApplication(SpringbootJavaApplication.class);
		springApplication.setBannerMode(Banner.Mode.OFF);
		springApplication.run(args);
    }

猜你喜欢

转载自blog.csdn.net/u013985664/article/details/85683998
今日推荐