[学习笔记] SpringMVC之SpringMVC拓展

# 学习 # · 2021-02-17

RestFul风格

1、RestFul的概念:是一个资源定位及资源操作的风格。不是标准也不是协议,只是一种风格。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。

2、RestFul的功能:

(1)资源:互联网所有的事物都可以被抽象为资源。可以通过不同的请求方式来实现不同的效果。

(2)资源操作:使用POST、DELETE、PUT、GET,使用不同方法对资源进行操作。

3、RestFul初体验:

(1)新建一个类 RestFulController。

@Controller
public class RestFulController {}

(2)在Spring MVC中可以使用 @PathVariable 注解,让方法参数的值对应绑定到一个URI模板变量上。

//映射访问路径
@RequestMapping("/commit/{p1}/{p2}")
public String index(@PathVariable int p1, @PathVariable int p2, Model model){

    int result = p1+p2;
    //Spring MVC会自动实例化一个Model对象用于向视图中传值
    model.addAttribute("msg", "结果:"+result);
    //返回视图位置
    return "index";

}

(3)访问测试。

4、使用路径变量的好处:

(1)使路径变得更加简洁。

(2)获得参数更加方便,框架会自动进行类型转换。

(3)通过路径变量的类型可以约束访问参数,如果类型不一样,则访问不到对应的请求方法,如这里访问是的路径是/commit/1/a,则路径与方法不匹配,而不会是参数转换失败。

5、使用method属性指定请求类型:

(1)增加一个方法,限定必须是POST请求。

@RequestMapping(value = "/hello",method = {RequestMethod.POST})
//或:@PostMapping("/hello")
public String index2(Model model){
   model.addAttribute("msg", "hello!");
   return "test";
}

(2)访问测试。

6、Spring MVC 的 @RequestMapping 注解能够处理 HTTP 请求的方法,比如 GET, PUT, POST, DELETE 以及 PATCH。所有的地址栏请求默认都会是 HTTP GET 类型的。

7、方法级别的注解变体有:

@GetMapping        //扮演@RequestMapping(method =RequestMethod.GET) 的一个快捷方式。
@PostMapping
@PutMapping
@DeleteMapping
@PatchMapping

使用Servlet API作为对象入参

1、在SpringMVC中,控制器可以不依赖任何ServletAPI对象,也可以将ServletAPI对象作为处理方法的入参使用。

2、通过HttpServletResponse进行输出:

@RequestMapping("/result/t1")
public void test1(HttpServletRequest req, HttpServletResponse rsp) throws IOException {
    rsp.getWriter().println("Hello,Spring BY servlet API");
}

3、通过HttpServletResponse实现重定向:

@RequestMapping("/result/t2")
public void test2(HttpServletRequest req, HttpServletResponse rsp) throws IOException {
    rsp.sendRedirect("/index.jsp");
}

4、通过HttpServletResponse实现转发:

@RequestMapping("/result/t3")
public void test3(HttpServletRequest req, HttpServletResponse rsp) throws Exception {
    //转发
    req.setAttribute("msg","/result/t3");
    req.getRequestDispatcher("/WEB-INF/jsp/test.jsp").forward(req,rsp);
}

5、通过HttpSession设置session:

@RequestMapping("/result/t4")
public void test3(Session session) {
    session.setAttribute("username","administrator");
}

静态资源处理

1、方法一:让Spring MVC不处理静态资源。修改Spring MVC配置文件:

<mvc:default-servlet-handler />

2、方法二:映射静态资源。

<!--
    mapping:将静态资源映射到指定的路径*(/statics)下
    location:本地静态资源文件所在的目录
-->
<mvc:resources mapping="/statics/**" location="/statics/"></mvc:resources>

异常处理

1、SpringMVC通过HandleExceptionResolver处理程序异常,包括处理器异常、数据绑定异常以及处理器执行时发生的异常。HandleExceptionResolver仅有一个接口方法。

resolveException(HttpServletRequest, HttpServletResponse, Object, Exception)

2、当异常发生时,SpringMVC会调用resolveException方法,并转到ModelAndView对应的视图中,作为一个异常报告页面反馈给用户。

3、局部异常处理:仅能处理指定Controller中的异常,使用@ExceptionHandle注解实现。

@RequestMapping(value="/exlogin.html",method=RequestMethod.GET)
public String exLogin(@RequestParam String userCode,@RequestParam String userPassword){
    //调用service方法,进行用户匹配
    User user = userService.login(userCode,userPassword);
    if(null == user){//登录失败
        throw new RuntimeException("用户名或者密码不正确!");
    }
    return "redirect:/user/main.html";
}

@ExceptionHandler(value={RuntimeException.class})
public String handlerException(RuntimeException e,HttpServletRequest req){
    req.setAttribute("e", e);
    return "error";
}

4、全局异常:可以使用SimpleMappingExceptionResolver来实现。它将异常类名映射为视图名,即发生异常时使用对应的视图报告异常。

<!--  全局异常处理 -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
    <property name="exceptionMappings">
        <props>
            <prop key="java.lang.RuntimeException">error</prop>
        </props>
    </property>
</bean>

Spring表单标签

1、通过Spring表单标签,可用很容易地将模型数据中的表单/命令对象绑定到HTML表达元素中。

2、在JSP文件中引用标签证明后即可使用表单标签:

<%@ taglib prefix="fm" uri="http://www.springframework.org/tags/form"%>

3、表单示例:

<fm:form method="post" modelAttribute="user">
    用户编码:<fm:input path="userCode"/><br/>
    用户名称:<fm:input path="userName"/><br/>
    用户生日:<fm:input path="birthday" Class="Wdate" readonly="readonly" onclick="WdatePicker();" class="Wdate"/><br/>
    用户角色:
    <fm:radiobutton path="userRole" value="1"/>系统管理员
    <fm:radiobutton path="userRole" value="2"/>经理
    <fm:radiobutton path="userRole" value="3" checked="checked"/>普通用户
    <br/>
    <input type="submit" value="保存"/>
</fm:form>

/**
 * modelAttribute:指定表单绑定的模型属性,默认为command
 * path:属性路径,表示表单对象属性
 * cssClass:表单组件对应的CSS样式类名
 * cssErrorClass:当提交表单后报错,采用的CSS样式
 * cssStyle:表单组件对应的CSS央视
 * htmlEscape:绑定的表单属性值是否对HTML特殊字符进行转换,默认为true
 */

4、Spring常用的表单标签:

<fm:form/>
<fm:input/>
<fm:password/>
<fm:hidden/>
<fm:select/>
......

数据校验

1、SpringMVC服务端数据校验的两种方式:

(1)利用Spring自带的验证框架。

(2)利用JSR 303实现。

2、JSR 303:

(1)是Java为Bean数据合法性校验所提供的标准框架。

(2)Spring MVC支持JSR 303标准的校验框架。

(3)JSR 303通过在Bean属性上标注校验注解指定校验规则,并通过标准的验证接口对Bean进行验证。

(4)注意:Spring本身没有提供JSR 303的实现。

3、JSR 303约束:

@Null    //被注释的元素必须为null
@NotNull    //被注释的元素必须不为null
@NotEmpty    //被注释的元素必须非空
@AssertTrue    //被注释的元素必须为 true
@AssertFalse    //被注释的元素必须为 false
@Min(value)    //被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@Max(value)    //被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@DecimalMin(value)    //被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@DecimalMax(value)    //被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@Size(max, min)    //被注释的元素的大小必须在指定的范围内
@Digits (integer, fraction)    //被注释的元素必须是一个数字,其值必须在可接受的范围内
@Past    //被注释的元素必须是一个过去的日期
@Future    //被注释的元素必须是一个将来的日期

4、JSR 303数据校验的实现:

(1)修改POJO,给需要验证的属性增加相应的校验注解。

public class User {
    private Integer id; //id

    @NotEmpty(message="用户编码不能为空")
    private String userCode; //用户编码

    @NotEmpty(message="用户名称不能为空")
    private String userName; //用户名称

    @NotNull(message="密码不能为空")
    @Length(min=6,max=10,message="用户密码长度为6-10")
    private String userPassword; //用户密码

    //省略其他代码
}

(2)在Controller中使用注解所声明的限制规则来进行数据校验。

@RequestMapping(value="/add.html",method=RequestMethod.POST)
//使用注解@Valid,SpringMVC在完成数据绑定后,执行数据工作
//@Valid注解之后,必须紧挨着一个BindingResult参数
public String addSave(@Valid User user,BindingResult bindingResult,HttpSession session){

    if(bindingResult.hasErrors()){
        System.out.println("add user validated has error");
        return "user/useradd";
    }

    if(userService.add(user)){
        return "redirect:/user/userlist.html";
    }

    return "user/useradd";
}

(3)修改View,实现错误信息的展示:

<fm:errors path="userName"/><br/>
用户名称:<fm:input path="userName"/> <br/>
<fm:errors path="userPassword"/><br/>
用户密码:<fm:password path="userPassword"/> <br/>

乱码问题解决

1、解决方法一:SpringMVC给我们提供了一个过滤器 , 可以在web.xml中配置。

<filter>
    <filter-name>encoding</filter-name>
       <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
       <init-param>
        <param-name>encoding</param-name>
           <param-value>utf-8</param-value>
       </init-param>
</filter>
<filter-mapping>
    <filter-name>encoding</filter-name>
       <url-pattern>/*</url-pattern>
</filter-mapping>

2、解决方法二:

(1)修改Tomcat配置文件,设置编码。

<Connector URIEncoding="utf-8" port="8080" protocol="HTTP/1.1"
          connectionTimeout="20000"
          redirectPort="8443" />

(2)自定义过滤器:

package com.demo.filter;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Map;

/**
* 解决get和post请求 全部乱码的过滤器
*/
public class GenericEncodingFilter implements Filter {

   @Override
   public void destroy() {}

   @Override
   public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
       //处理response的字符编码
       HttpServletResponse myResponse=(HttpServletResponse) response;
       myResponse.setContentType("text/html;charset=UTF-8");

       // 转型为与协议相关对象
       HttpServletRequest httpServletRequest = (HttpServletRequest) request;
       // 对request包装增强
       HttpServletRequest myrequest = new MyRequest(httpServletRequest);
       chain.doFilter(myrequest, response);
  }

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

   }

}

//自定义request对象,HttpServletRequest的包装类
class MyRequest extends HttpServletRequestWrapper {

   private HttpServletRequest request;
   //是否编码的标记
   private boolean hasEncode;
   //定义一个可以传入HttpServletRequest对象的构造函数,以便对其进行装饰
   public MyRequest(HttpServletRequest request) {
       super(request);// super必须写
       this.request = request;
  }

   // 对需要增强方法 进行覆盖
   @Override
   public Map getParameterMap() {
       // 先获得请求方式
       String method = request.getMethod();
       if (method.equalsIgnoreCase("post")) {
           // post请求
           try {
               // 处理post乱码
               request.setCharacterEncoding("utf-8");
               return request.getParameterMap();
          } catch (UnsupportedEncodingException e) {
               e.printStackTrace();
          }
      } else if (method.equalsIgnoreCase("get")) {
           // get请求
           Map<String, String[]> parameterMap = request.getParameterMap();
           if (!hasEncode) { // 确保get手动编码逻辑只运行一次
               for (String parameterName : parameterMap.keySet()) {
                   String[] values = parameterMap.get(parameterName);
                   if (values != null) {
                       for (int i = 0; i < values.length; i++) {
                           try {
                               // 处理get乱码
                               values[i] = new String(values[i]
                                      .getBytes("ISO-8859-1"), "utf-8");
                          } catch (UnsupportedEncodingException e) {
                               e.printStackTrace();
                          }
                      }
                  }
              }
               hasEncode = true;
          }
           return parameterMap;
      }
       return super.getParameterMap();
  }

   //取一个值
   @Override
   public String getParameter(String name) {
       Map<String, String[]> parameterMap = getParameterMap();
       String[] values = parameterMap.get(name);
       if (values == null) {
           return null;
      }
       return values[0]; // 取回参数的第一个值
  }

   //取所有值
   @Override
   public String[] getParameterValues(String name) {
       Map<String, String[]> parameterMap = getParameterMap();
       String[] values = parameterMap.get(name);
       return values;
  }
}

(3)在web.xml中配置这个过滤器:

<filter>
    <filter-name>encoding</filter-name>
       <filter-class>com.demo.filter.GenericEncodingFilter</filter-class>
       <init-param>
        <param-name>encoding</param-name>
           <param-value>utf-8</param-value>
       </init-param>
</filter>
<filter-mapping>
    <filter-name>encoding</filter-name>
       <url-pattern>/*</url-pattern>
</filter-mapping>
如无特殊说明,本博所有文章均为博主原创。

如若转载,请注明出处:一木林多 - https://www.l5v.cn/archives/254/

评论