欧美三级电影完整|亚洲一二三四久久|性爱视频精品一区二区免费在线观看|国产精品啪啪视频|婷婷六月综合操人妻视频网站|99爱免费视频在线观看|美女一级片在线观看|北京熟女88av|免费看黄色A级电影|欧美黄色毛片儿

深入Spring MVC,還得知道這些

2023-04-12


文章目錄

  • 寫在前面
  • 處理器映射
  • 上下文參數(shù)
  • 無注解下獲取參數(shù)
  • 使用注解@RequestParam獲取參數(shù)
  • 數(shù)組參數(shù)
  • JSON參數(shù)
  • URL包含參數(shù)
  • 數(shù)據(jù)轉(zhuǎn)換器
  • 參數(shù)轉(zhuǎn)換流程
  • Converter實踐
  • 自定義轉(zhuǎn)換器
  • domain類
  • 控制器接口
  • 瀏覽器驗證
  • postman驗證
  • HttpMessageConverter說明
  • 數(shù)據(jù)驗證
  • Hibernate Validator驗證
  • 添加依賴
  • 驗證實體
  • 引入注解@Valid
  • 模擬訪問
  • 自定義驗證
  • 驗證機制
  • 驗證實體
  • 自定義驗證器
  • 控制器方法
  • 模擬訪問
  • 數(shù)據(jù)模型
  • 視圖和視圖解析器
  • thymeleaf配置
  • jsp配置
  • 文件上傳
  • StandardServletMultipartResolver
  • yml
  • 控制器方法示例
  • 接口設(shè)計
  • 攔截器
  • XSS過濾
  • 配置文件
  • XssFilterConfig
  • XssFilter
  • XssHttpServletRequestWrapper
  • EscapeUtil
  • HTMLFilter
  • 防重復(fù)提交
  • 國際化
  • 結(jié)尾

在《初識 Spring MVC,知道這些就夠了》中,我從應(yīng)用的角度粗略總結(jié)了一下Spring MVC的知識,這一篇章我將從更為細致的角度去總結(jié)一下相關(guān)知識。我打算從處理器映射、上下文參數(shù)、數(shù)據(jù)轉(zhuǎn)換器、數(shù)據(jù)驗證、數(shù)據(jù)模型、視圖和視圖解析器、文件上傳、攔截器、國際化等方面分別進行總結(jié),并總結(jié)一些實際應(yīng)用案例。


寫在前面


強大的Spring已經(jīng)做到了框架的天花板,作為一個java工程師必須深入了解Spring,我?guī)е鴮W(xué)習(xí)的心態(tài),將Spring MVC又重新深入了解一下,希望帶來更深層次的思索,授業(yè)解惑。


處理器映射


在上一章的介紹中,我們已經(jīng)知道一個請求從客戶端過來,會找到請求對應(yīng)的控制器,那么這一過程是怎么實現(xiàn)的,我接下來就要分析一下這個過程。
我把springboot工程中l(wèi)ogging.level.org.springframework日志級別改為trace,這樣我們可以看到系統(tǒng)啟動時,RequestMappingHandlerMapping組件會檢測到所有@Controller控制器的@RequestMapping方法,日志如下圖:


14:29:42.373 [restartedMain] TRACE o.s.w.s.m.m.a.RequestMappingHandlerMapping - [detectHandlerMethods,292] - 
	c.r.w.c.d.c.DemoDialogController:
	{GET [/demo/modal/parent]}: parent()
	{GET [/demo/modal/layer]}: layer()
	{GET [/demo/modal/check]}: check()
	{GET [/demo/modal/table]}: table()
	{GET [/demo/modal/form]}: form()
	{GET [/demo/modal/radio]}: radio()
	{GET [/demo/modal/frame2]}: frame2()
	{GET [/demo/modal/dialog]}: dialog()
	{GET [/demo/modal/frame1]}: frame1()

當一個請求"/captcha/captchaImage"發(fā)送到服務(wù)器的時候,DispatcherServlet會先根據(jù)請求找到"sysCaptchaController"組件,然后找到該組件的"getKaptchaImage"方法進行處理。



這些都歸功于@RequestMapping、@PostMapping、@GetMapping、@PutMapping、@DeleteMapping等注解,我以GetMapping為例看下源碼:


@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RequestMapping(
    method = {RequestMethod.GET}
)
// 僅限于get請求了
public @interface GetMapping {
    @AliasFor(
        annotation = RequestMapping.class
    )
    // 配置請求映射名稱
    String name() default "";

    @AliasFor(
        annotation = RequestMapping.class
    )
    String[] value() default {};

    @AliasFor(
        annotation = RequestMapping.class
    )
    // 通過路徑映射
    String[] path() default {};

    @AliasFor(
        annotation = RequestMapping.class
    )
    // 限定參數(shù)
    String[] params() default {};

    @AliasFor(
        annotation = RequestMapping.class
    )
    // 限定請求頭
    String[] headers() default {};

    @AliasFor(
        annotation = RequestMapping.class
    )
    // 限定提交類型,即本方法消費什么類型的數(shù)據(jù),如application/json
    String[] consumes() default {};

    @AliasFor(
        annotation = RequestMapping.class
    )
    // 限定響應(yīng)內(nèi)容類型,即指定生產(chǎn)什么類型的數(shù)據(jù)
    String[] produces() default {};
}

上下文參數(shù)


在實際應(yīng)用過程中,獲取參數(shù)有多種方式,最常見的有如下幾種:


  • 無注解下獲取參數(shù)
  • 使用注解@RequestParam獲取參數(shù)
  • 數(shù)組參數(shù)
  • JSON參數(shù)
  • URL包含參數(shù)

無注解下獲取參數(shù)

控制器方法


@Controller
@RequestMapping("/test")
public class TestController {

    @RequestMapping("/hello")
    @ResponseBody
    public String hello(String username) {
        return "hello, " + username;
    }
}

瀏覽器請求


http://127.0.0.1:8080/test/hello?username=lilei



postman請求



由此可以看出,只需要控制器接口參數(shù)名稱和http請求參數(shù)名稱保持一致。



使用注解@RequestParam獲取參數(shù)

控制器方法


@RequestMapping("/hi")
    @ResponseBody
    public String hi(@RequestParam("user_name") String username) {
        return "hi, " + username;
    }

瀏覽器請求


http://127.0.0.1:8080/test/hi?user_name=lilei





postman請求



@RequestParam注解實現(xiàn)了控制器參數(shù)和http請求參數(shù)的映射關(guān)系,且默認情況下參數(shù)不能為空,可以使用required=false屬性進行設(shè)置。



數(shù)組參數(shù)

控制器方法


@RequestMapping("/welcome")
    @ResponseBody
    public String welcome(String[] usernames) {
        for (String username : usernames) {
            System.out.println(username);
        }
        return "welcome";
    }

瀏覽器請求


http://127.0.0.1:8080/test/welcome?usernames=lilei,lili,ligang



postman請求



后臺輸出



JSON參數(shù)

@Data
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
    private String city;
}
@RequestMapping("/user")
    @ResponseBody
    public String user(@RequestBody User user) {
        System.out.println(user.toString());
        return user.toString();
    }

postman請求



@RequestBody注解表示控制器方法接收前端提交的JSON數(shù)據(jù)格式的請求體,JSON請求體參數(shù)名稱和User屬性名稱保持一致。



URL包含參數(shù)

控制器方法


@RequestMapping("/viewuser/{id}")
    @ResponseBody
    public String viewuser(@PathVariable("id") String id) {
        System.out.println(id);
        return id;
    }

瀏覽器請求


http://127.0.0.1:8080/test/viewuser/1




數(shù)據(jù)轉(zhuǎn)換器


在上下文參數(shù)章節(jié),我們得知控制器接收參數(shù)時進行了自動轉(zhuǎn)換,這是因為spring內(nèi)置了很多數(shù)據(jù)轉(zhuǎn)換器,比如最長用的:StringHttpMessageConverter、MappingJackson2HttpMessageConverter。


參數(shù)轉(zhuǎn)換流程


  • Converter,普通轉(zhuǎn)換器接口
  • Formatter,格式化轉(zhuǎn)換器
  • GenericConverter,可以將參數(shù)轉(zhuǎn)換為數(shù)組

在SpringMVC中,這三類接口實現(xiàn)可通過注冊機接口注冊,注冊后控制器就可以獲取對應(yīng)的轉(zhuǎn)換器來實現(xiàn)參數(shù)的轉(zhuǎn)換。


在Spring Boot中,使用WebMvcAutoConfiguration中內(nèi)部類WebMvcAutoConfigurationAdapter的addFormatters方法來注冊。



// WebMvcAutoConfigurationAdapter
    public void addFormatters(FormatterRegistry registry) {
        ApplicationConversionService.addBeans(registry, this.beanFactory);
    }
    // ApplicationConversionService
    public static void addBeans(FormatterRegistry registry, ListableBeanFactory beanFactory) {
        Set beans = new LinkedHashSet();
        beans.addAll(beanFactory.getBeansOfType(GenericConverter.class).values());
        beans.addAll(beanFactory.getBeansOfType(Converter.class).values());
        beans.addAll(beanFactory.getBeansOfType(Printer.class).values());
        beans.addAll(beanFactory.getBeansOfType(Parser.class).values());
        Iterator var3 = beans.iterator();

        while(var3.hasNext()) {
            Object bean = var3.next();
            if (bean instanceof GenericConverter) {
                registry.addConverter((GenericConverter)bean);
            } else if (bean instanceof Converter) {
                registry.addConverter((Converter)bean);
            } else if (bean instanceof Formatter) {
                registry.addFormatter((Formatter)bean);
            } else if (bean instanceof Printer) {
                registry.addPrinter((Printer)bean);
            } else if (bean instanceof Parser) {
                registry.addParser((Parser)bean);
            }
        }

    } 
    
   

在Spring Boot的工程中,只需要定義一個Converter組件即可。



知道了轉(zhuǎn)換器的原理以及注冊機制后,那么我們實踐一下如何自定義一個數(shù)據(jù)轉(zhuǎn)換器呢,比如我們傳送一個分數(shù)參數(shù),我們需要將分數(shù)按照A、B、C、D、E分等級(grade)。


Converter實踐

只需要定義一個@Component組件即可。


自定義轉(zhuǎn)換器

@Component
public class StringToGradeConverter implements Converter {

    @Override
    public Grade convert(String source) {
        // http字符串參數(shù)
        Long s = Long.parseLong(source);
        if (s < 60) {
            return new Grade(s, "E");
        } else if (s < 70) {
            return new Grade(s, "D");
        } else if (s < 80) {
            return new Grade(s, "C");
        } else if (s < 90) {
            return new Grade(s, "B");
        } else if (s < 100) {
            return new Grade(s, "A");
        } else {
            return new Grade(s, "A+");
        }

    }
}

domain類

public class Grade {

    public Grade(Long score, String grade) {
        this.fs = score;
        this.dj = grade;
    }
    private Long fs;
    private String dj;

    public Long getFs() {
        return fs;
    }

    public void setFs(Long fs) {
        this.fs = fs;
    }

    public String getDj() {
        return dj;
    }

    public void setDj(String dj) {
        this.dj = dj;
    }

    @Override
    public String toString() {
        return "Grade{" +
                "fs=" + fs +
                ", dj='" + dj + '\'' +
                '}';
    }
}

控制器接口

@RestController
@RequestMapping("/test")
public class GradeController {

    public static final Logger logger = LoggerFactory.getLogger(GradeController.class);


    @RequestMapping("/converter")
    public String converter(Grade grade){
        logger.info(grade.toString());
        return grade.toString();
    }

}

瀏覽器驗證

http://127.0.0.1:8080/test/converter?grade=88



返回結(jié)果:



postman驗證


HttpMessageConverter說明

HttpMessageConverter接口負責(zé)將http請求體轉(zhuǎn)換成對應(yīng)的java對象。
比如@RequestBody注解,通過HttpMessageConverter來實現(xiàn)請求體和java對象之間的解析。


數(shù)據(jù)驗證


參數(shù)轉(zhuǎn)換后,處理器還可以進行參數(shù)驗證,以保障后邊進行的業(yè)務(wù)邏輯處理。


Hibernate Validator驗證

添加依賴


        org.springframework.boot
        spring-boot-starter-validation
    

驗證實體

public class User {
    private Long id;
    @NotNull(message = "名稱不能為空")
    private String name;
    private Integer age;
    private String email;
    private String city;

    public Long getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", email='" + email + '\'' +
                ", city='" + city + '\'' +
                '}';
    }
}

引入注解@Valid

@RequestMapping("/user")
    @ResponseBody
    public String user(@Valid @RequestBody User user) {
        System.out.println(user.toString());
        return user.toString();
    }

模擬訪問


后臺報org.springframework.web.bind.MethodArgumentNotValidException異常



自定義驗證

驗證機制


Validator驗證器接口,實現(xiàn)這個接口定義自己的驗證器。
@InitBinder注解用來綁定驗證器,在控制器方法調(diào)用前會調(diào)用。



驗證實體

package com.example.entity;

public class User {

    private Long id;
    private String name;
    private Integer age;
    private String email;
    private String city;

    public Long getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", email='" + email + '\'' +
                ", city='" + city + '\'' +
                '}';
    }
}

自定義驗證器

package com.example.config;

import com.example.entity.User;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;

public class UserValidator implements Validator {
    // 需要驗證的實體類型,true驗證,false否
    @Override
    public boolean supports(Class clazz) {
        return clazz.equals(User.class);
    }

    /**
     * 驗證規(guī)則
     * @param target 驗證對象
     * @param errors 錯誤對象
     */
    @Override
    public void validate(Object target, Errors errors) {

        // 驗證年齡必須大于18
        User user = (User) target;
        if (user.getAge() != null && user.getAge() < 18) {
            errors.rejectValue("age", null, "未成年");
            return;
        }

    }

}

控制器方法

package com.example.web;

import com.example.config.UserValidator;
import com.example.entity.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.validation.Valid;

@Controller
public class UserController {

    /**
     * 綁定自定義驗證器
     * 其它方法調(diào)用前,先執(zhí)行該綁定方法
     * @param binder
     */
    @InitBinder
    public void initBinder(WebDataBinder binder) {
        binder.setValidator(new UserValidator());

    }

    /**
     * 驗證器實踐接口
     * @param user
     * @return
     */
    @RequestMapping("/user/validator")
    @ResponseBody
    public String user(@Valid @RequestBody User user) {
        System.out.println(user.toString());
        return user.toString();
    }
}

如何在控制器方法獲取到驗證的錯誤信息,需要使用org.springframework.validation.Errors



// 可以通過Errors獲取驗證信息
    @RequestMapping("/user/validator")
    @ResponseBody
    public String user(@Valid @RequestBody User user, Errors errors) {
        System.out.println(user.toString());
        for (ObjectError error : errors.getAllErrors()) {
            System.out.println(error.getDefaultMessage());
        }

        return user.toString();
    }

模擬訪問


后臺日志:


Resolved [org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument [0] in public java.lang.String com.example.web.UserController.user(com.example.entity.User): [Field error in object 'user' on field 'age': rejected value [14]; codes [user.age,age,java.lang.Integer,]; arguments []; default message [未成年]] ]

數(shù)據(jù)模型


數(shù)據(jù)模型的作用是綁定數(shù)據(jù),為后面的視圖渲染做準備。





我在實際項目中常用ModelMap,如下方法所示:


@GetMapping("/edit/{deptId}")
    public String edit(@PathVariable("deptId") Long deptId, ModelMap mmap)
    {
        mmap.put("dept", deptService.selectDeptById(deptId));
        return prefix + "/edit";
    }

視圖和視圖解析器


視圖的作用是渲染數(shù)據(jù)模型展示給用戶,分為邏輯視圖(如InternalResourceViewResolver)和非邏輯視圖(如MappingJackson2JsonView)。
默認的視圖解析器配置:org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
邏輯視圖中我們經(jīng)常使用的是jthymeleaf和jsp。



thymeleaf配置

spring:
  # 模板引擎
  thymeleaf:
    mode: HTML
    encoding: utf-8
    # 禁用緩存
    cache: false

默認配置:


package org.springframework.boot.autoconfigure.thymeleaf;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.http.MediaType;
import org.springframework.util.MimeType;
import org.springframework.util.unit.DataSize;

@ConfigurationProperties(
    prefix = "spring.thymeleaf"
)
public class ThymeleafProperties {
    private static final Charset DEFAULT_ENCODING;
    public static final String DEFAULT_PREFIX = "classpath:/templates/";
    public static final String DEFAULT_SUFFIX = ".html";
    private boolean checkTemplate = true;
    private boolean checkTemplateLocation = true;
    private String prefix = "classpath:/templates/";
    private String suffix = ".html";
    private String mode = "HTML";
    ......   
}

jsp配置

spring:
  # jsp config
  mvc:
    view:
      prefix: /WEB-INF/views
      suffix: .jsp

文件上傳


在spring-boot-autoconfigure包內(nèi)的org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration類中,已經(jīng)默認配置了StandardServletMultipartResolver,所以我們只需要簡單的配置一下yml參數(shù)即可。


StandardServletMultipartResolver

@Configuration(
    proxyBeanMethods = false
)
@ConditionalOnClass({Servlet.class, StandardServletMultipartResolver.class, MultipartConfigElement.class})
@ConditionalOnProperty(
    prefix = "spring.servlet.multipart",
    name = {"enabled"},
    matchIfMissing = true
)
@ConditionalOnWebApplication(
    type = Type.SERVLET
)
@EnableConfigurationProperties({MultipartProperties.class})
public class MultipartAutoConfiguration {
    private final MultipartProperties multipartProperties;

    public MultipartAutoConfiguration(MultipartProperties multipartProperties) {
        this.multipartProperties = multipartProperties;
    }

    @Bean
    @ConditionalOnMissingBean({MultipartConfigElement.class, CommonsMultipartResolver.class})
    public MultipartConfigElement multipartConfigElement() {
        return this.multipartProperties.createMultipartConfig();
    }

    @Bean(
        name = {"multipartResolver"}
    )
    @ConditionalOnMissingBean({MultipartResolver.class})
    public StandardServletMultipartResolver multipartResolver() {
        StandardServletMultipartResolver multipartResolver = new StandardServletMultipartResolver();
        multipartResolver.setResolveLazily(this.multipartProperties.isResolveLazily());
        return multipartResolver;
    }
}

yml

spring:
  servlet:
    # 上傳下載配置
    multipart:
      # 單個文件大小
      max-file-size: 1MB
      # 設(shè)置總上傳的文件大小
      max-request-size: 10MB

控制器方法示例

@PostMapping("/common/upload")
    @ResponseBody
    public HashMap uploadFile(MultipartFile file) throws Exception
    {
        HashMap ajax = new HashMap();
        try
        {
            // 上傳文件路徑,windows和linux有區(qū)別,本示例在windows環(huán)境
            String filePath = "D:/uploadPath";
            // 設(shè)定文件名稱,實際中需要是動態(tài)擴展的,比如添加目錄層級
            String fileName = file.getOriginalFilename();
            File desc = new File(filePath + File.separator + fileName);
            // 關(guān)鍵是這句代碼,拷貝文件
            file.transferTo(desc);
            // pathFileName和url實際中也需要動態(tài)處理
            String pathFileName = "需要返回的路徑";
            String url = "http://127.0.0.1:8080/" + pathFileName;

            ajax.put("code", 0);
            ajax.put("fileName", pathFileName);
            ajax.put("url", url);

        }
        catch (Exception e)
        {
            ajax.put("code", 500);
        }
        return ajax;
    }

接口設(shè)計


攔截器


實際項目中常用的攔截器有防跨站攻擊(Xss)、防重復(fù)提交。


XSS過濾

配置文件

xss:
  # 過濾開關(guān)
  enabled: true
  # 非過濾鏈接(多個用逗號分隔)
  excludes: /platform/notice/*
  # 過濾鏈接
  urlPatterns: /user/*,/role/*,/dept/*

XssFilterConfig

@Configuration
public class XssFilterConfig
{
    @Value("${xss.enabled}")
    private String enabled;

    @Value("${xss.excludes}")
    private String excludes;

    @Value("${xss.urlPatterns}")
    private String urlPatterns;

    @SuppressWarnings({ "rawtypes", "unchecked" })
    @Bean
    public FilterRegistrationBean xssFilterRegistration()
    {
        // 注冊過濾器到servlet 3.0+容器
        FilterRegistrationBean registration = new FilterRegistrationBean();
        // 設(shè)置dispatcher類型,此處為request,
        registration.setDispatcherTypes(DispatcherType.REQUEST);
        // 設(shè)置過濾器對象
        registration.setFilter(new XssFilter());
        // 過濾請求路徑
        registration.addUrlPatterns(StringUtils.split(urlPatterns, ","));
        registration.setName("xssFilter");
        registration.setOrder(Integer.MAX_VALUE);
        Map initParameters = new HashMap();
        initParameters.put("excludes", excludes);
        initParameters.put("enabled", enabled);
        // 設(shè)置過濾器初始化參數(shù)
        registration.setInitParameters(initParameters);
        return registration;
    }
}

XssFilter

public class XssFilter implements Filter {
    /**
     * 排除鏈接
     */
    public List excludes = new ArrayList<>();

    /**
     * xss過濾開關(guān)
     */
    public boolean enabled = false;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 獲取排除鏈接
        String tempExcludes = filterConfig.getInitParameter("excludes");
        String tempEnabled = filterConfig.getInitParameter("enabled");
        if (StringUtils.isNotEmpty(tempExcludes)) {
            String[] url = tempExcludes.split(",");
            for (int i = 0; url != null && i < url.length; i++) {
                excludes.add(url[i]);
            }
        }
        if (StringUtils.isNotEmpty(tempEnabled)) {
            enabled = Boolean.valueOf(tempEnabled);
        }
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse resp = (HttpServletResponse) response;
        // 處理需要排除過濾的鏈接
        if (handleExcludeURL(req, resp)) {
            chain.doFilter(request, response);
            return;
        }
        // 包裝請求對象
        XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest) request);
        chain.doFilter(xssRequest, response);
    }

    /*
     * 處理需要排除過濾的鏈接
     *   開關(guān)關(guān)閉,所有鏈接都不過濾
     *   excludes 參數(shù)為空,默認全部過濾
     *   在excludes 參數(shù)中找到具體鏈接,則進行過濾
     *   默認全部過濾
     */
    private boolean handleExcludeURL(HttpServletRequest request, HttpServletResponse response) {
        // 開關(guān)關(guān)閉返回true
        if (!enabled) {
            return true;
        }
        // 排除鏈接為空返回false
        if (excludes == null || excludes.isEmpty()) {
            return false;
        }
        String url = request.getServletPath();
        for (String pattern : excludes) {
            Pattern p = Pattern.compile("^" + pattern);
            Matcher m = p.matcher(url);
            if (m.find()) {
                return true;
            }
        }
        // 默認返回false
        return false;
    }

    @Override
    public void destroy() {

    }
}

XssHttpServletRequestWrapper

/*
 *包裝請求對象
 *  處理參數(shù)特殊字符
 */
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
    /**
     * @param request
     */
    public XssHttpServletRequestWrapper(HttpServletRequest request) {
        super(request);
    }

    @Override
    public String[] getParameterValues(String name) {
        String[] values = super.getParameterValues(name);
        if (values != null) {
            int length = values.length;
            String[] escapseValues = new String[length];
            for (int i = 0; i < length; i++) {
                // 防xss攻擊和過濾前后空格
                escapseValues[i] = EscapeUtil.clean(values[i]).trim();
            }
            return escapseValues;
        }
        return super.getParameterValues(name);
    }
}

EscapeUtil

若依框架工具類:EscapeUtil



HTMLFilter

若依框架工具類:HTMLFilter



防重復(fù)提交

主要思路是對相同請求的參數(shù)是否一致,以及兩次請求(參數(shù)一致)的時間差進行對比(小于10秒,可變)。使用緩存或者session以請求url為key,進行存儲參數(shù)和時間戳,每次請求會更新當前緩存信息。


若依框架攔截器:SameUrlDataInterceptor



國際化


請移閱“面向全球的用戶,我們該怎么辦”


結(jié)尾


自此SpringMVC的主要知識點就梳理完成了,我知道了這些,再也不怕別人問我SpringMVC相關(guān)知識了。




本文僅代表作者觀點,版權(quán)歸原創(chuàng)者所有,如需轉(zhuǎn)載請在文中注明來源及作者名字。

免責(zé)聲明:本文系轉(zhuǎn)載編輯文章,僅作分享之用。如分享內(nèi)容、圖片侵犯到您的版權(quán)或非授權(quán)發(fā)布,請及時與我們聯(lián)系進行審核處理或刪除,您可以發(fā)送材料至郵箱:service@tojoy.com