SpringMVC笔记本(3)

自定义拦截器

实现HandlerInterceptor接口

preHandle()方法

签名:booleanpreHandle(HttpServletRequest, HttpServletResponse, Object)

在执行目标handler方法之前执行[请求进入控制器之前],如果返回true,则继续执行后续拦截器和目标handler方法;如果返回false则不执行。注意:返回false时最好借助转发或重定向等方式为客户端提供一个响应页面。

postHandle()方法

签名:voidpostHandle(HttpServletRequest, HttpServletResponse, Object, ModelAndView)

在执行目标handler方法之后、渲染视图之前执行。

afterCompletion()方法

在渲染视图之后、返回响应之前执行。

拦截器作用:拦截用户的请求,或者拦截一些非法操作!

步骤定义拦截器

publicclass MyInterceptor implements HandlerInterceptor {

 

   //在进入控制器之前执行,只有返回true,才进行后续的执行!handler表示要拦截的那个方法。

   @Override

   publicboolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)

        throws Exception {

      System.out.println("preHandle-----");

      returntrue;

   }

   // 控制器执行完成,进入jsp之前

   @Override

   publicvoid postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,

        ModelAndView modelAndView) throws Exception {

      System.out.println("postHandle-----");

     

   }

   // 执行jsp之后

   @Override

   publicvoid afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)

        throws Exception {

      System.out.println("afterCompletion-----");

   }

}

配置拦截器

在springmvc.xml 中进行配置

 

第一种配置:这样表示所有请求都被拦截!

   <mvc:interceptors>

      <bean class="com.xypuxing.interceptor.MyInterceptor"></bean>

   </mvc:interceptors>

第二种配置:设置哪些拦截

   <mvc:interceptors>

      <mvc:interceptor>

         <!-- 只拦截哪些路径-->

         <mvc:mapping path="/hello"/>

         <!-- 拦截器 -->

         <bean class="com.xypuxing.interceptor.MyInterceptor"></bean>

      </mvc:interceptor>

   </mvc:interceptors>

注意:preHandle(); 此方法应该注意返回的true,还是false

案例:

 

控制器

   @RequestMapping("hello")

   public String hello(){

      // 返回的视图名称

      System.out.println("hello----");

      return"hello";

   }

Hello.jsp

<body>

   <% System.out.println("hello.jsp"); %>

 </body>

 

浏览器请求被拦截的hello,从控制台发现

 

拦截器栈【多个拦截器】

配置多个拦截器的时候,则就会形成拦截器栈

   <mvc:interceptors>

      <!-- 拦截器 -->

      <bean class="com.xypuxing.interceptor.MyInterceptor"></bean>

      <bean class="com.xypuxing.interceptor.MyInterceptor2"></bean>

   </mvc:interceptors>

 

结果:

 

多个拦截器执行的顺序是:先进后出!

他们的执行顺序跟springmvc.xml 中配置拦截器的顺序有关系!

 

设置先配置拦截器A在配置拦截器B执行顺序为

preHandle(A) -->  preHandle(B) --> 控制器方法  --> postHandle(B)

--> postHanle(A) --> JSP --> afterCompletion(B)--> afterCompletion(A)

 

登录验证

需求:用户登录之后,才能进行数据查询,否则不能进行查询

确保程序能够访问login.jsp,以及能够访问login的控制器

在springmvc.xml 中配置

   <mvc:interceptors>

      <!-- 拦截器 -->

      <mvc:interceptor>

         <!-- 拦截所有 -->

         <mvc:mapping path="/**"/>

         <!-- 以下配置路径不需要拦截 -->

         <mvc:exclude-mapping path="/index"/>

         <mvc:exclude-mapping path="/login"/>

         <bean class="com.xypuxing.interceptor.MyInterceptor"></bean>

      </mvc:interceptor>

   </mvc:interceptors>

 

 

页面

<body>

   <form action="login" method="post">

      username:<input type="text" name="uname"/><br>

      pwd:<input type="password" name="pwd"/><br>

      <input type="submit" value="登录"/><br>

   </form>

</body>

Login 控制器

   @RequestMapping("login")

   public String login(Student stu,HttpSession session){

      if (stu.getUname().equals("admin")) {

         session.setAttribute("stu", stu);

         return"hello";

      }

      return"login";

   }

  

   @RequestMapping("findAll")

   @ResponseBody

   public List<Student> findAll(){

      List<Student> list = new ArrayList<>();

      list.add(new Student(1, "张三", "123"));

      list.add(new Student(2, "李四", "123"));

      list.add(new Student(3, "王五", "123"));

      System.out.println(list);

      returnlist;

   }

Hello.jsp

<script type="text/javascript" src="js/jquery-1.7.2.js"></script>

<script type="text/javascript">

   $(function(){

      $.ajax({

         type:"post",

         url:"findAll",

         dataType:"json",

         success:function(data){

            for(var i = 0;i<data.length;i++){

                var con = "<tr><td>"+data[i].id+"</td><td>"+data[i].uname+"</td><td>"+data[i].pwd+"</td></tr>"

                $("#tab").append(con);

            }

         }

      })

   })

</script>

</head>

<body>

   <table id="tab">

   </table>

</body>

拦截器

publicclass MyInterceptor implements HandlerInterceptor {

 

    //在进入控制器之前执行,只有返回true,才进行后续的执行!

    @Override

    publicboolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)

           throws Exception {

       HttpSession session = request.getSession();

       Student stu = (Student) session.getAttribute("stu");

       if (stu!=null) {

           returntrue;

       }

       response.sendRedirect("error.jsp");

       returnfalse;

    }

}

 

数据类型转换

日期类型:如果实体类中有日期类型:

   // 学生的生日

   private Datebirth;

在进行数据提交的时候,则可能会出现如下情况

SpringMVC笔记本(3)

400 的原因是数据类型不匹配,必须借助@DateTimeFormat(pattern="yyyy-mm-dd") 进行转换!

页面

<body>

   <form action="login" method="post">

      username:<input type="text" name="uname"/><br>

      pwd:<input type="password" name="pwd"/><br>

      birth:<input type="text" name="birth"><br>

      <input type="submit" value="登录"/><br>

   </form>

</body>

 

实体类

 

publicclass Student {

   private Integer id;

   private String uname;

   private String pwd;

   @DateTimeFormat(pattern="yyyy-mm-dd")

   private Date birth;

}

控制器

   @RequestMapping("login")

   public String login(Student stu,HttpSession session){

      System.out.println(stu+"login");

      if (stu.getUname().equals("admin")) {

        session.setAttribute("stu", stu);

        return"hello";

      }

      return"login";

   }

 

还可以添加数字类型的格式化

   @NumberFormat(pattern="#,###,###.##")

   private Double salary;

<form action="login" method="post">

      username:<input type="text" name="uname"/><br>

      pwd:<input type="password" name="pwd"/><br>

      birth:<input type="text" name="birth"><br>

      salary:<input type="text" name="salary"><br>

      <input type="submit" value="登录"/><br>

   </form>

 

SpringMVC和Spring容器

Web.xml

<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xmlns="http://java.sun.com/xml/ns/javaee"

    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"

    id="WebApp_ID" version="2.5">

 

    <context-param>

       <param-name>contextConfigLocation</param-name>

       <param-value>classpath:spring.xml</param-value>

    </context-param>

 

    <listener>

       <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

    </listener>

 

    <servlet>

       <servlet-name>springDispatcherServlet</servlet-name>

       <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

       <init-param>

           <param-name>contextConfigLocation</param-name>

           <param-value>classpath:springmvc.xml</param-value>

       </init-param>

       <load-on-startup>1</load-on-startup>

    </servlet>

 

    <!-- Map all requests to the DispatcherServlet for handling -->

    <servlet-mapping>

       <servlet-name>springDispatcherServlet</servlet-name>

       <url-pattern>/</url-pattern>

    </servlet-mapping>

 

    <!-- 字符编码过滤器 -->

    <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>

    <filter>

       <filter-name>HiddenHttpMethodFilter</filter-name>

       <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>

    </filter>

    <filter-mapping>

       <filter-name>HiddenHttpMethodFilter</filter-name>

       <url-pattern>/*</url-pattern>

    </filter-mapping>

</web-app>

 

Spring.xml 和 springmvc.xml 配置文件

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

   xmlns:context="http://www.springframework.org/schema/context"

   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd

      http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">

   <context:component-scan base-package="com.xypuxing">

      <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>

   </context:component-scan>

</beans>

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

   xmlns:context="http://www.springframework.org/schema/context"

   xmlns:mvc="http://www.springframework.org/schema/mvc"

   xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd

      http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd

      http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">

 

   <context:component-scan base-package="com.xypuxing" use-default-filters="false">

      <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>

   </context:component-scan>

</beans>

 

Service 层

package com.xypuxing.service;

 

import org.springframework.stereotype.Service;

 

@Service

publicclass BookService {

   public BookService(){

      System.out.println("BookService被创建了");

   }

}

Controller层

package com.xypuxing.controller;

 

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Controller;

 

import com.xypuxing.service.BookService;

@Controller

publicclass BookController {

  

   @Autowired

   BookService bookService;

  

   public BookController() {

      System.out.println("BookController 被创建了。");

   }

}

 

如果在spring.xml 和springmvc.xml 中同时都扫描 com.xypuxing则会出现实体类会被扫描两次的情况!

RESTFUL----CRUD

REST

概述

Representational State Transfer——表现层(资源)状态转化。是目前最流行的一种互联网软件架构风格。它倡导结构清晰、符合标准、易于理解、扩展方便的Web架构体系,主张严格按照HTTP协议中定义的规范设计结构严谨的Web应用架构体系。由于REST所倡导的理念让Web应用更易于开发和维护,更加优雅简洁,所以正得到越来越多网站的采用。

基本概念

资源(Resources):网络上的一个实体,或者说是网络上的一个具体信息。它可以是一段文本、一张图片、一首歌曲、一种服务,总之就是一个具体的存在。可以用一个URI(统一资源定位符)指向它,每种资源对应一个特定的 URI 。要获取这个资源,访问它的URI就可以,因此 URI 即为每一个资源的独一无二的识别符。

表现层(Representation):把资源具体呈现出来的形式,叫做它的表现层(Representation)。比如,文本可以用txt格式表现,也可以用HTML格式、XML格式、JSON格式表现,甚至可以采用二进制格式。

状态转化(StateTransfer):每发出一个请求,就代表了客户端和服务器的一次交互过程。HTTP协议,是一个无状态协议,即所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,必须通过某种手段,让服务器端发生“状态转化”(StateTransfer)。而这种转化是建立在表现层之上的,所以就是 “表现层状态转化”。具体说,就是 HTTP 协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。它们分别对应四种基本操作:GET 用来获取资源POST 用来新建资源PUT 用来更新资源DELETE 用来删除资源

REST风格的URL

REST风格要求我们不要再使用问号键值对的方式携带请求参数,而是从URL地址中获取。下面我们进行一下对比:

①保存操作

TRADITIONAL URL

http://localhost:8080/CRUD/saveEmp

POST请求

RESTFUL URL

http://localhost:8080/CRUD/emp

POST请求

②删除操作

TRADITIONAL URL

http://localhost:8080/CRUD/removeEmp?empId=2

GET请求

RESTFUL URL

http://localhost:8080/CRUD/emp/2

DELETE请求

③更新操作

TRADITIONAL URL

http://localhost:8080/CRUD/updateEmp

POST请求

RESTFUL URL

http://localhost:8080/CRUD/emp

PUT请求

④查询操作(查询单个对象)

TRADITIONAL URL

http://localhost:8080/CRUD/getEmp?empId=2

GET请求

RESTFUL URL

http://localhost:8080/CRUD/emp/2

GET请求

 

REST风格URL地址的好处

TRADITIONAL URL

http://localhost:8080/CRUD/removeEmp?empId=2

RESTFUL URL

http://localhost:8080/CRUD/emp/2

含蓄,安全

使用问号键值对的方式给服务器传递数据太明显,容易被人利用来对系统进行破坏。使用REST风格携带数据不再需要明显的暴露数据的名称。

风格统一

URL地址整体格式统一,从前到后始终都使用斜杠划分各个内容部分,用简单一致的格式表达语义。

无状态

在调用一个接口(访问、操作资源)的时候,可以不用考虑上下文,不用考虑当前状态,极大的降低了系统设计的复杂度。

严谨,规范

严格按照HTTP1.1协议中定义的请求方式本身的语义进行操作。

简洁,优雅

过去做增删改查操作需要设计4个不同的URL,现在一个就够了

传统方式

RESTFUL 风格

/CRUD/saveEmp

/CRUD/emp配合POST请求方式

/CRUD/removeEmp?empId=2

/CRUD/emp/2配合DELETE请求方式

/CRUD/updateEmp

/CRUD/emp配合PUT请求方式

/CRUD/editEmp?empId=2

/CRUD/emp/2配合GET请求方式

 

丰富的语义

通过URL地址就可以知道资源之间的关系。

http://localhost:8080/shop

http://localhost:8080/shop/product

http://localhost:8080/shop/product/cellPhone

http://localhost:8080/shop/product/cellPhone/iPhone

 

环境搭建

配置web.xml

<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

   xmlns="http://java.sun.com/xml/ns/javaee"

   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"

   id="WebApp_ID" version="2.5">

 

   <!-- The front controller of this Spring Web application, responsible for

      handling all application requests -->

   <servlet>

      <servlet-name>springDispatcherServlet</servlet-name>

      <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

      <init-param>

        <param-name>contextConfigLocation</param-name>

        <param-value>classpath:springmvc.xml</param-value>

      </init-param>

      <load-on-startup>1</load-on-startup>

   </servlet>

 

   <!-- Map all requests to the DispatcherServlet for handling -->

   <servlet-mapping>

      <servlet-name>springDispatcherServlet</servlet-name>

      <url-pattern>/</url-pattern>

   </servlet-mapping>

 

   <!-- 字符编码过滤器 -->

   <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>

   <filter>

      <filter-name>HiddenHttpMethodFilter</filter-name>

      <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>

   </filter>

   <filter-mapping>

      <filter-name>HiddenHttpMethodFilter</filter-name>

      <url-pattern>/*</url-pattern>

   </filter-mapping>

</web-app>

配置springmvc.xml

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"

   xmlns:mvc="http://www.springframework.org/schema/mvc"

   xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd

      http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd

      http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">

 

   <context:component-scan base-package="com.xypuxing" />

   <mvc:default-servlet-handler />

   <mvc:annotation-driven />

   <bean

      class="org.springframework.web.servlet.view.InternalResourceViewResolver">

      <!-- 配置视图解析器前缀 -->

      <property name="prefix" value="/WEB-INF/pages/"></property>

      <!-- 配置视图解析器后缀 -->

      <property name="suffix" value=".jsp"></property>

   </bean>

</beans>

 

 

在WebContent目录下创建一个页面访问控制

<body>

   <a href="hello">hello</a>

</body>

 

创建控制器

package com.xypuxing.controller;

 

import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.RequestMapping;

@Controller

publicclass HelloController {

  

   @RequestMapping("hello")

   public String index(){

      return"success";

   }

}


SpringMVC笔记本(3)

导入实体类,dao

SpringMVC笔记本(3)

员工列表展示

页面

Index.jsp

 

<a href="emps">查找所有员工</a>

控制器

package com.xypuxing.controller;

 

@Controller

publicclass EmpController {

    @Autowired

    EmployeeDao employeeDao;

   

    @RequestMapping("emps")

    public String getEmps(Model model){

       Collection<Employee> all = employeeDao.getAll();

       model.addAttribute("emps",all);

       return"list";

    }

}

 

<body>

   <h1>员工列表</h1>

   <table>

      <tr>

         <th>ID</th>

         <th>lastName</th>

         <th>email</th>

         <th>gender</th>

         <th>departmentName</th>

         <th>EDIT</th>

         <th>DELETE</th>

      </tr>

      <c:forEach items="${emps }" var="emp">

         <tr>

            <td>${emp.id }</td>

            <td>${emp.lastName}</td>

            <td>${emp.email }</td>

            <td>${emp.gender==0?"":"" }</td>

            <td>${emp.department.departmentName }</td>

            <td><a href="emp/${emp.id }">edit</a></td>

            <td><a href="emp/${emp.id }" class="delBtn">delete</a></td>

         </tr>

      </c:forEach>

   </table>

</body>

 

员工添加

在list.jsp页面添加一个连接,跳转到添加控制器,来到添加页面,保存之后,在列表中展示。在来到添加之前,一定要先查出所有部门信息!

<a href="toaddemppage">添加员工</a>

该控制器查出所有的部门信息并保存

   @RequestMapping("toaddemppage")

   public String toAddPage(Model model){

      // 查出所有部门信息

      Collection<Department> departments = departmentDao.getDepartments();

      // 保存所有部门信息,到页面显示

      model.addAttribute("depts", departments);

      return"add";

   }

 

Add.jsp

<body>

    <form action="emp" method="post">

       lastName:<input type="text" name="lastName" /><br>

       email:<input type="text" name="email" /><br>

       gender:<br />

       男:<input type="radio" name="gender" value="1" /><br />

       女:<input type="radio" name="gender" value="0" /><br />

       dept<select  name="department.id">

           <c:forEach items="${depts }" var="deptItem">

              <option value="${deptItem.id }">${deptItem.departmentName }</option>

           </c:forEach>

       </select><br>

       <input type="submit" value="保存" />

    </form>

</body>

添加数据的控制器

@RequestMapping("emp")

   public String addEmp(Employee employee){

      employeeDao.save(employee);

      return"redirect:/emps";

   }

       

员工修改

点击edit按钮,来到员工修改页面,修改的时候要加载当前员工的信息。

@RequestMapping("/emp/{id}")

   public String updateEmp(@PathVariable("id")Integer id,Model model) {

      Employee employee = employeeDao.get(id);

      System.out.println("要修改的员工:" + employee);

      // 将查询到的数据保存到作用域中

      model.addAttribute("employee", employee);

      // 查出所有部门信息

      Collection<Department> departments = departmentDao.getDepartments();

      model.addAttribute("depts", departments);

      return"edit";

   }

<form action="${employee.id }" method="post">

      <input type="hidden" name="_method" value="put"/>

      lastName:<input type="text" value="${employee.lastName }" name="lastName" /><br>

      email:<input type="text" value="${employee.email }" name="email" /><br>

      gender:<br />

      <c:if test="${employee.gender==1 }">

         男:<input type="radio" checked="checked" name="gender" value="1" /><br />

         女:<input type="radio" name="gender" value="0" /><br />

      </c:if>

      <c:if test="${employee.gender==0 }">

         男:<input type="radio" name="gender" value="1" /><br />

         女:<input type="radio" checked="checked" name="gender" value="0" /><br />

      </c:if>

      dept<select  name="department.id">

         <c:forEach items="${depts }" var="deptItem">

            <option value="${deptItem.id }">${deptItem.departmentName }</option>

         </c:forEach>

      </select><br>

      <input type="submit" value="修改" />

   </form>

@RequestMapping(value="/emp/{id}",method=RequestMethod.PUT)

   public String updEmp(Employee employee) {

      employeeDao.save(employee);

      return"redirect:/emps";

   }

 

隐藏域:   <input type="hidden" name="_method"value="put"/>

1.      是因为有了相同的控制器路径!

2.      根据处理的业务不同,应该使用它Restful的不同请求方式!put请求方式表单没有提供,所以必须加入隐藏域!

 

员工删除

页面list.jsp

    <form id="deleteForm" action="emp/${emp.id }" method="post">

       <input type="hidden" name="_method" value="DELETE" />

    </form>

</body>

<script type="text/javascript">

    $(function(){

       $(".delBtn").click(function(){

           $("#deleteForm").attr("action",this.href);

           $("#deleteForm").submit();

           returnfalse;

       }) 

    })

</script>

控制器 

@RequestMapping(value="emp/{id}",method=RequestMethod.DELETE)

    public String delEmp(@PathVariable("id")Integer id){

       employeeDao.delete(id);

       return"redirect:/emps";

    }

 

 

Restful:风格的CRUD:

最主要的是注意put,delete 请求!

Put:修改

Delete :删除

以上两个操作都需要隐藏域的参与:

<input type="hidden" name="_method"value="DELETE" />

<!-- 配置restful一个过滤器设计到一个隐藏域提交 -->

   <filter>

      <filter-name>HiddenHttpMethodFilter</filter-name>

   <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>

   </filter>

   <filter-mapping>

      <filter-name>HiddenHttpMethodFilter</filter-name>

      <url-pattern>/*</url-pattern>

   </filter-mapping>