建立maven项目
选择archetype:maven-archetype-webapp
注:若是建立项目过慢,输入<archetypeCatalog,internal>
在建立项目Properties的时候javascript
补全工程文件目录
java,resource,并mark directory为Re/Source rootcss
在pom中引入依赖html
<!-- 编译版本修改成1.8 --> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <!-- Spring版本锁定 --> <spring.version>5.0.2.RELEASE</spring.version> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> <version>2.0</version> <scope>provided</scope> </dependency> </dependencies>
<web-app> <!-- SpringMVC的核心控制器 --> <servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- 配置Servlet的初始化参数,指定springmvc配置文件在類路徑下,建立springMVC容器 --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param> <!-- 配置servlet启动时加载对象 --> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <!-- 在servlet映射中添加dispatcherServlet --> <servlet-name>dispatcherServlet</servlet-name> <!-- 整个网站所有的Servlet都要通过核心控制器 --> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
輸入<servlet
生成兩行,第二行為沒寫完的<
光標下移,然後輸入servlet-class補全,然後在<servlet-class></servlet-class>
内輸入
DispatcherServlet,就可自動生成。init-param與servlet-mapping都须要本身手動輸入,不自動匹配。
提示:init-param不须要輸入,若是沒有指定使用默认值:/WEB-INF/<servlet-name>-servlet.xml
前端
以上配置完畢,就能够部署在Tomcat上。當然只有一個index.jsp頁面罷了java
<a/>
標簽<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <body> <h2>Hello World!</h2> <a href="hello" >新手程序,可是我好像都懂hhhh</a> </body> </html>
/hello
package cn.itcast.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; /** * 控制器标记 */ @Controller public class HellowController { /** * 接收请求路徑为`hello`千萬別寫反斜杠/ * @return */ @RequestMapping(path = "/hello") public String sayHello() { System.out.println("Hello SpringMVC!!"); return "success"; } }
在WEB-INF中創建pages文件夾
裏面放置跳轉的jsp頁面,這個路徑由SpringMVC-servlet.xml配置文件中 視圖解析器 決定的。程序员
新建success JSP頁面
【跳轉頁面】web
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <h2>Welcome to SpringMVC!</h2> </body> </html>
<?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"> <!-- 只扫描带有controller注解的控制器 --> <context:component-scan base-package="com.atguigu.mybatis" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> <!-- 视图解析器InternalResourceViewResolver --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/pages/"></property> <property name="suffix" value=".jsp"></property> </bean> <!-- 处理动态,静态资源两个MVC标签,重要**不僅僅是注解還表明注冊各種SpringMVC組件xxx器** --> <mvc:annotation-driven></mvc:annotation-driven> <mvc:default-servlet-handler/> </beans>
<mvc:annotation-driven>
说明
在 SpringMVC 的各个组件中,处理器映射器、处理器适配器、视图解析器称为 SpringMVC 的三大组件。
使用<mvc:annotation-driven>
自动加载 RequestMappingHandlerMapping(处理映射器)
和RequestMappingHandlerAdapter(处理适配器)可用在SpringMVC.xml配置文件中使用 <mvc:annotation-driven>
替代注解处理器和适配器的配置。ajax
個人理解:
前端控制器DispatchServlet:只是中轉站,傳入request請求,返回response響應。這個中間經它的調用有
1.處理器映射器2.處理器適配器3.視圖解析器4.動靜態頁面spring
處理器映射器handlermapping:將傳入的請求路徑進行解析,生成這個請求路徑+背後所有须要的其余請求的執行鏈Chain。返回給前端控制器。数据库
處理器適配器HandlerAdapter:將由前端控制器轉發的執行鏈中的所有servlet執行,返回Model結果數據和View须要的頁面
視圖解析器ViewResolver:將由前端控制器轉發的View頁面 拼裝 為完整的頁面訪問路徑
視圖:渲染–由前端控制器裝載model數據到返回的具體頁面request域中
注:爲什麽這個前端控制器這麽累
,是因爲和Spring IOC容器一樣,下降這些組件閒的相互耦合.
出现位置: 类上:请求 URL 的第一级访问目录。此处不写的话,就至关于应用的根目录。写的话须要以/开头。 功用:使 URL 訪問能够按照模块化管理: 例如: 帐户模块: /account/add /account/update /account/delete ... 订单模块: /order/add /order/update /order/delete 實例: @RequestMapping("/account") ,使 URL 更加精细【將重複性的類名從方法上的requestmapping中抽取出來放在上面而已】。 方法上:请求 URL 的第二级访问目录。 實例: @RequestMapping(path="/add"),path,可寫可不寫,若是是一個參數時 属性: value:用于指定请求的 URL。它和 path 属性的做用是同样的。 method:用于指定请求的方式(get/post/head/put/patch/delete/options/trace)可單個,可多個值。 實例: @RequestMapping(value="/saveAccount",method=RequestMethod.POST) @RequestMapping(value="/saveAccount",method={RequestMethod.POST,RequestMethod.GET}) 注:<a></a>使用get方法 params:用于指定限制请求参数的条件。它支持简单的表达式。要求请求参数的 key 和 value 必须和 配置的如出一辙。 可單多 半實例: params = {"accountName"},表示请求参数必须有 accountName params = {"moeny!100"},表示请求参数中 money 不能是 100。 headers:用于指定请求消息头的条件 限制。 半實例: headers = {"Accept"} 注意: 以上四个属性只要出现 2 个或以上时,他们的关系是与的关系。
做用: 指定(從前臺傳入後臺的)參數名称,给控制器中的形参賦值。 属性: value=name:请求参数中的名称。 required:请求参数中是否必须提供此参数。默认值為true必须提供,若是不提供将报错。 defaultValue:默認值 實例: @RequestMapping("/useRequestParam") public String useRequestParam( @RequestParam("name")String username, @RequestParam(value="age",required=false)Integer age) { System.out.println(username+","+age); return "success"; }
GET請求方法是將全部參數封裝在url上,而POST方法則是封裝成一個對象【因此Form表單是POST請求】
請求體包含Form表單内容,controller函數形參只能寫一個@RequestBody String body。
做用: 用于获取请求体内容。直接使用获得是 key=value&key=value...结构的数据。 get 请求方式不适用。 【異步的時候會用到。傳遞Json數據,封裝的時候用到@RequestBody】 属性: required:是否必须有请求体。默认值是:true。当取值为 true 时,get 请求方式会报错。 若是取值 为 false,get 请求获得是 null。
controller.java
@RequestMapping("/testRequestBody") public String testRequestBody(@RequestBody String body){ System.out.println("执行了..."); System.out.println(body); return "success"; }
實例:若是表單為,username:abc,age:12。則請求體為:username=abc&age=12
做用: 用于獲取 請求路徑 中的占位符`{}`内容(/usePathVariable/100)獲取100這樣就不须要input。 也不须要key=value的形式獲取。 属性: name=value:用于指定 url 中占位符名称。 required:是否必须提供占位符 實例: controller函數上的@RequestMapping("/usePathVariable/{id}") 中的{id}就是 url 占位符。 url 支持占位符是 spring3.0 以后加入的。是 springmvc 支持 rest 风格 URL 的一个重要标志。
jsp 代码:
<!-- PathVariable 注解 --> <a href="springmvc/usePathVariable/100">pathVariable 注解</a>
controller 代碼:
@RequestMapping("/usePathVariable/{id}") public String usePathVariable(@PathVariable("id") Integer id){ System.out.println(id); return "success"; }
Restful風格:
個人理解——用不一样的請求方法+佔位符來區分相同請求路徑調用的不一样方法——>用最簡單的方法來實現複雜重複代碼
對於緩存的優點是——共用一個局部緩存,因爲路徑上訪問的都是這個Controller類對象,利於管理。
Rest案例:
因为浏览器 form 表单只支持 GET 与 POST 请求(a標簽支持的是GET),而 DELETE、PUT 等 method 并不支持
Spring3.0 添加了一个过滤器,能够将浏览器请求改成指定的请求方式,发送给咱们的控制器方法,使得支持 GET、POST、PUT 与 DELETE 请求。
這樣就能够實現@PathVaribale()注解的功用,創建Restful風格代碼。
【除了這個filter,還能够通過WebClient類,直接調用靜態方法模擬各種請求方式。以及瀏覽器插件也能够作到】
使用方式:
filter彻底實現類
原理:雖然form表單只能發post或者get
但下面有一行input 隱藏域<input type="hidden" name="_method" value="PUT">
這個會被filter攔截到,從而將post請求轉換為put請求。
.jsp
<!-- 保存 --> <form action="springmvc/testRestPOST" method="post"> 用户名称:<input type="text" name="username"><br/> <!-- <input type="hidden" name="_method" value="POST"> --> <input type="submit" value=" 保存 "> </form> <hr/> <!-- 更新 --> <form action="springmvc/testRestPUT/1" method="post"> 用户名称:<input type="text" name="username"><br/> <input type="hidden" name="_method" value="PUT"> <input type="submit" value=" 更新 "> </form> <hr/> <!-- 删除 --> <form action="springmvc/testRestDELETE/1" method="post"> <input type="hidden" name="_method" value="DELETE"> <input type="submit" value=" 删除 "> </form> <hr/> <!-- 查询一个 --> <form action="springmvc/testRestGET/1" method="post"> <input type="hidden" name="_method" value="GET"> <input type="submit" value=" 查询 "> </form>
controller
/** * post 请求:保存 * @param username * @return */ @RequestMapping(value="/testRestPOST",method=RequestMethod.POST) public String testRestfulURLPOST(User user){ System.out.println("rest post"+user); return "success"; } /** * put 请求:更新 * @param username * @return */ @RequestMapping(value="/testRestPUT/{id}",method=RequestMethod.PUT) public String testRestfulURLPUT(@PathVariable("id")Integer id,User user){ System.out.println("rest put "+id+","+user); return "success"; } /** * post 请求:删除 * @param username * @return */ @RequestMapping(value="/testRestDELETE/{id}",method=RequestMethod.DELETE) public String testRestfulURLDELETE(@PathVariable("id")Integer id){ System.out.println("rest delete "+id); return "success"; } /** * post 请求:查询 * @param username * @return */ @RequestMapping(value="/testRestGET/{id}",method=RequestMethod.GET) public String testRestfulURLGET(@PathVariable("id")Integer id){ System.out.println("rest get "+id); return "success"; }
属性: value 指定Header名称(前端具备的属性), required 实例: public getHeader(@RequestHeader(value=“Accept”)String header){}
属性: value 指定Cookie名称(前端/session具备的属性), required 实例: public getCookie(@RequestCookie(value=“JSESSIONID”)String cookie){}
位置: 方法头上,controller方法形参前 做用: 有该注解的方法(不须要写@RequestMapping),会在请求路径url的controller方法==先执行==。 属性: value 获取传入参数的key值,key能够是数据库类名,也能够是map<key,value>的key 应用场景:在表单提交用户资料修改的时候,数据库POJO类的某些属性是定死的,确定不容许修改的,那么这些属性值如何赋予? 【先将不可修改的数据项查询出来,直接传递给请求路径url的controller方法】就會用到这个注解
实例:
@RequestMapping(/user/save) public String testModelAttribute(User user){ } @ModelAttribute public User searchUser(String name){ User user = new User(); user.setName(); user.setAge(); user.setDate(); return user }
@ModelAttribute public User serchUser(String name)内set赋值的属性值会经过return user传入
@RequestMapping(/user/save) public String testModelAttribute(User user)
而且这个请求路径url的controller方法会再从网页前端获取user属性值,并覆盖掉@ModeAttribute的set置入的属性值。
@RequestMapping(/user/save) public String testModelAttribute(@ModelAttribute("abc") User user){ } @ModelAttribute public void searchUser(String name,Map<String,User> map){ User user = new User(); user.setName(); user.setAge(); user.setDate(); map.put("abc",user) }
做用: 用于controller类的多个方法间参数共享。 属性: name=value:用于指定存入的属性名称 type:用于指定存入的数据类型。 位置: controller类上注解
实例:
<!-- SessionAttribute 注解的使用 --> <a href="springmvc/testPut">存入 SessionAttribute</a> <hr/> <a href="springmvc/testGet">取出 SessionAttribute</a> <hr/> <a href="springmvc/testClean">清除 SessionAttribute</a>
注:Model接口是替代Request类的存在,下降耦合,该接口有一个彻底实现类ModelMap/ExtendedModelMap,可用于取出Session对象内属性
@Controller("sessionAttributeController") @RequestMapping("/springmvc") @SessionAttributes(value={"username","password"},types={Integer.class}) public class SessionAttributeController { /** * 把数据存入 SessionAttribute * @param model * @return * Model 是 spring 提供的一个接口,该接口有一个实现类 ExtendedModelMap * 该类继承了 ModelMap,而 ModelMap 就是 LinkedHashMap 子类 */ @RequestMapping("/testPut") public String testPut(Model model){ model.addAttribute("username", "泰斯特"); model.addAttribute("password","123456"); model.addAttribute("age", 31); //跳转以前将数据保存到 username、password 和 age 中,由于注解@SessionAttribute 中有 这几个参数 return "success"; @RequestMapping("/testGet") public String testGet(ModelMap model){ System.out.println(model.get("username")+";"+model.get("password")+";"+model.get("a ge")); return "success"; } @RequestMapping("/testClean") public String complete(SessionStatus sessionStatus){ sessionStatus.setComplete(); return "success"; } }
表单中请求参数都是基于 key=value
SpringMVC 绑定请求参数的过程是经过把表单提交请求参数,做为前端控制器中的方法的参数进行绑定,内置映射規則。
基本类型参数 : 包括基本类型和String类型 POJO类型参数 : 包括实体类,以及关联的实体类 数组和集合类型参数 : 包括 List 结构和 Map 结构的集合(包括数组) SpringMVC 绑定请求参数是自动实现的,可是要想使用,必须遵循使用要求。
基本类型或者String类型: 要求参数名称必须和控制器中方法的形参名称保持一致。(严格区分大小写) POJO类型,或者它的关联对象: 要求表单中参数名称和 POJO 类的属性名称保持一致。而且控制器方法的参数类型是 POJO 类型。 集合类型,有两种方式: 第一种: 要求集合类型的请求参数必须在 POJO 中。在表单中请求参数名称要和 POJO 中集合属性名称相同。 给 List 集合中的元素赋值,使用下标。 给 Map 集合中的元素赋值,使用键值对。 第二种: 接收的请求参数是 json 格式数据。须要借助一个注解实现 注意: 它还能够实现一些数据类型自动转换。内置转换器在:org.springframework.core.convert.support包
Java數據類型轉換以下:
少许參數
一兩個方法所需的參數,直接在url中使用?``&
傳遞便可
只要求,傳遞的參數名與方法的參數名相同便可。
多個參數
少许參數能够用? aaa=value1 & bbb=value2 & ...
與符號來傳遞多個參數到後臺
若是再多,能够用JavaBean來傳遞【使用form表單提交請求,而不是href=url】
JavaBean要求:
1.實現序列化接口 implements Serializable
2.全部的屬性有Set Get ToString方法
JSP form表單要求:
input name屬性值必須是與Javabean類的屬性名相同。不一样則JavaBean的Set方法就找不到封裝失敗
Controller類方法將 參數寫為JavaBean類形參便可。(真的方便啊)
實例:
@RequestMapping("/saveAccount") public String saveAccount(Account account){ System.out.println("执行了..."); System.out.println(account); return "success"; }
Javabean包含關聯類屬性
若是Javabean的屬性關聯另外一個對象,則在JSP 表單中name值=關聯類.屬性名
例如:A 有 B類 屬性,B類有2個屬性 name age,則 JSP表單中 name=“b.name”//name="b.age"便可
當然,必定要生成對應屬性的Get/Set方法,toString。
List/Map集合屬性
前提:對應屬性的Get/Set方法,toString
實例:
JavaBean Account: private List<User> list; private Map<String,User> map; JavaBean User: private String uname; private Integer age; JSP: <form action="param/saveAccount" method="post"> 姓名:<input type="text" name="username" /><br/> 密码:<input type="text" name="password" /><br/> 金额:<input type="text" name="money" /><br/> 用户姓名:<input type="text" name="list[0].uname" /><br/> 用户年龄:<input type="text" name="list[0].age" /><br/> 用户姓名:<input type="text" name="map['one'].uname" /><br/> 用户年龄:<input type="text" name="map['one'].age" /><br/> <input type="submit" value="提交" /> </form>
SpringMVC 能够實現 2000/10/20 自動轉換為 日期類型
但不能識別 2000-10-20
package cn.itcast.converter; import org.springframework.core.convert.converter.Converter; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; //繼承Converter接口 public class StringToDateConverter implements Converter<String,Date> { /** * 页面传入的字符串s,返回转换完的Date类型变量df。 * 下面为实现Converter接口的声明函数 * @param s * @return */ @Override public Date convert(String s) { //判斷字符串 if (s == null){ throw new RuntimeException("空数据内容"); } DateFormat df = new SimpleDateFormat("yyyy-mm-dd"); try { return df.parse(s); } catch (Exception e) { throw new RuntimeException("格式错误"); } } }
<!-- 配置自定义转换器,不覆盖,不写也默认启动--> <bean id="conversionService2" class="org.springframework.context.support.ConversionServiceFactoryBean"> <property name="converters"> <set> <bean class="cn.itcast.converter.StringToDateConverter"></bean> </set> </property> </bean> <!-- 配置spring开启注解mvc的支持,開啓自定義轉換器設置,不覆蓋默認Spring Core轉換器 這裏默認開啓conversionService(Spring Core)--> <mvc:annotation-driven conversion-service="conversionService2"></mvc:annotation-driven>
Request Response對象
直接在Controller方法的形參中聲明便可获得
HttpServletRequest request,
HttpServletResponse response,
HttpSession session
/** * 原生的API * @return */ @RequestMapping("/testServlet") public String testServlet(HttpServletRequest request, HttpServletResponse response){ System.out.println("执行了..."); System.out.println(request); HttpSession session = request.getSession(); System.out.println(session); ServletContext servletContext = session.getServletContext(); System.out.println(servletContext); System.out.println(response); return "success"; }
SpringMVC能够通過 設置過濾器filter(CharacterEncodingFilter)攔截全部的servlet請求,進行request處理。
web.xml
<!--配置解决中文乱码的过滤器 放置在listener servlet配置前,Spring的context-param*配置后--> <filter> <filter-name>characterEncodingFilter</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>characterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
就不须要在每個Servlet裏對request對象進行設置
开启EL表达式
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false"%>
Controller类中的方法返回字符串能够指定逻辑视图的名称,根据视图解析器为实际视图的访问地址
实例:
controller.java
@RequestMapping(value="/hello") public String sayHello() { System.out.println("Hello SpringMVC!!"); // 跳转到XX页面 return "success"; }
若是控制器的方法返回值编写成void,执行程序报404的异常,默认查找JSP页面没有找到。
可是controller方法确实执行了。404异常请求的页面为————方法名.jsp
例如请求的方法是
@@RequestMapping(value="/user")
@RequestMapping(value="/initUpdate")
则异常为 找不到默认跳转【前缀】user/initUpdate【.jsp】
的页面。
消除404:
1.手动请求跳转页面【转发】
问题1:手动request不通过视图解析器,因此要写完整路径
问题2:若是这个controller方法后续还有其余方法执行,若是不想执行,则写return;
便可
2.重定向页面
转发是能够直接进入到具体路径的页面,重定向是从新发了一个新的请求
新的请求是不容许直接进入具体路径的页面须要request.getContextPath()
3.直接回复字节流至客户端
实例:
@RequestMapping("/testVoid") public void testVoid(HttpServletRequest request, HttpServletResponse response) throws Exception { System.out.println("testVoid方法执行了..."); // 手动请求转发————手动request不通过视图解析器,因此要写完整路径 //request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request,response); // 重定向 // response.sendRedirect(request.getContextPath()+"/index.jsp"); // 设置中文乱码 response.setCharacterEncoding("UTF-8"); response.setContentType("text/html;charset=UTF-8"); // 直接会进行响应 response.getWriter().print("你好"); //阻断后续其余方法执行 return; }
ModelAndView对象是Spring提供的一个对象,能够用来调整具体的JSP视图
我的理解:与手动转发请求的区别只是在因而否经过springmvc的视图解析器,与返回字符串跳转页面也没什么区别。
实例
controller.java
@RequestMapping(value = "/findAll") public ModelAndView findAll() throws Exception { ModelAndView mv = new ModelAndView(); // 跳转到list.jsp的页面 mv.setViewName("list"); // 模拟从数据库中查询全部的用户信息 List<User> users = new ArrayList<>(); User user1 = new User(); user1.setUsername("张三"); user1.setPassword("123"); User user2 = new User(); user2.setUsername("赵四"); user2.setPassword("456"); users.add(user1); users.add(user2); // 添加对象 mv.addObject("users", users); return mv;
jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <!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> <h3>查询全部的数据</h3> <c:forEach items="${ users }" var="user"> ${ user.username } </c:forEach> </body> </html>
1.forward请求转发
重点!!:不走视图解析器,写完整路径,以及能够转发至controller类其余方法的请求路径
实例:
@RequestMapping("/delete") public String delete() throws Exception { System.out.println("delete方法执行了..."); // return "forward:/WEB-INF/pages/success.jsp"; return "forward:/user/findAll"; }
2.redirect重定向
重点!!:redirect底层封装了request.getContextPath(),因此不须要写了【重定向也能够到controller类其余方法的请求路径】
实例:
@RequestMapping("/count") public String count() throws Exception { System.out.println("count方法执行了..."); return "redirect:/add.jsp"; // return "redirect:/user/findAll"; }
多应用于ajax异步请求,接受json格式数据在服务器。
配置springmvc.xml
<!-- 第一种配置 --> <!-- 设置根目录下某些子目录的文件(静态资源)不拦截 --> <!-- <mvc:resources location="/css/" mapping="/css/**"/> <mvc:resources location="/images/" mapping="/images/**"/> <mvc:resources location="/js/" mapping="/js/**"/> --> <!-- 第二种 --> <!-- 处理动态,静态资源两个MVC标签,annotation-driven不僅僅是开启注解還表明注冊各種SpringMVC組件xxx器 --> <mvc:annotation-driven></mvc:annotation-driven> <mvc:default-servlet-handler/>
location元素表示webapp目录下的包下的全部文件
mapping元素表示以/static开头的全部请求路径,如/static/a 或者/static/a/b
注意:<mvc:default-servlet-handler/>
必须放在最后
controller.java
@RequestMapping("/testJson") public void testJson(@RequestBody String body) { System.out.println(body); }
Ajax.jsp
<header> <script> //绑定btn按钮的单击事件 $(function(){ $("#btn").click(function(){ // alert("hello btn"); // 发送ajax请求 $.ajax({ // 编写json格式,设置属性和值 url:"user/testAjax", contentType:"application/json;charset=UTF-8", data:'{"username":"hehe","password":"123","age":30}', //后端相应的返回值类型 dataType:"json", type:"post", //成功传至服务器后,Ajax执行的success函数 success:function(data){ } }); }); }); </script> </header> <body> <button id="btn">发送ajax的请求</button> </body>
进阶版:使用@ResponseBody 注解实现将 controller 方法返回对象转换为 json 响应给客户端
前置要求:jackson3个jar包(annotations,databind,core)
Springmvc 默认用 MappingJacksonHttpMessageConverter 对 json 数据进行转换,须要加入 jackson 包。
pom.xml的dependencies标签内引入依赖
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.0</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.9.0</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.9.0</version> </dependency>
controller.java
@RequestMapping("/testJson") //@ResponseBody 注在返回值类型Address前,自动将Address类型转换为json格式数据响应给客户端 public @ResponseBody Address testJson(@RequestBody Address address) { //客户端发送ajax请求,传入的是json字符串(请求体内)由SpringMVC框架自动转换封装到JavaBean中 System.out.println(address); address.setAddressName("上海"); return address; }
客户端发送ajax请求,传入到controller方法的是json字符串(请求体内)由SpringMVC框架自动转换封装到JavaBean中
@ResponseBody
注在返回值类型Address前,自动将Address类型(Javabean)转换为json格式数据响应给客户端
ajax.jsp
$(function(){ // 绑定点击事件 $("#btn").click(function(){ $.ajax({ url:"user/testJson", contentType:"application/json;charset=UTF-8", data:'{"addressName":"哈哈","addressNum":100}', dataType:"json", type:"post", success:function(data){ alert(data); alert(data.addressName); } }); }); });
A form 表单的 enctype(表单请求正文的类型) 取值必须是:multipart/form-data (默认值是:application/x-www-form-urlencoded) B method 属性取值必须是 Post (get方法是将请求体写在URL里的。有大小限制) C 提供一个文件选择域<input type=”file” />
不管是传输字符串,仍是传输文件,都是经过form表单,其实文件只是长度很长的字符串罢了。 当 form 表单的 enctype=”application/x-www-form-urlencoded”时, form 表单的正文内容是键值对+&: key=value&key=value&key=value 当 form 表单的 enctype 取值为 Mutilpart/form-data 不是默认值时,request.getParameter()将失效。 请求正文内容就变成: 每一部分都是 MIME 类型描述的正文 -----------------------------7de1a433602ac 分界符 Content-Disposition: form-data; name="userName" 协议头 aaa 协议的正文(文件内容) -----------------------------7de1a433602ac 那么咱们的工做就是,解析Post请求方法的请求体,将文件内容、文件名拆分出来,而后在服务器指定路径下创建同名文件
本身来写很麻烦,借助第三方工具实现上传
使用SpringMVC框架内置MultipartFile对象
使用 Commons-fileupload 组件实现文件上传,须要导入该组件相应的支撑 jar 包:Commons-fileupload 和commons-io。
commons-io 不属于文件上传组件的开发 jar 文件,但Commons-fileupload 组件从 1.1 版本开始依赖commons-io包。
<dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.1</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.4</version> </dependency>
<h3>文件上传</h3> <form action="user/fileupload" method="post" enctype="multipart/form-data"> 选择文件:<input type="file" name="upload"/><br/> <input type="submit" value="上传文件"/> </form>
/** * 文件上传 * @throws Exception */ @RequestMapping(value = "/fileupload") public String fileupload(HttpServletRequest request) throws Exception { // 定义服务器端上传文件的目录 最后的/写不写都行 String path = request.getSession().getServletContext().getRealPath("/uploads/"); // 建立File对象,一会向该路径下上传文件【注意是在tomcat服务器下而不是Target】 File file = new File(path); // 判断路径是否存在,若是不存在,建立该路径 if (!file.exists()) { file.mkdirs(); } // 建立磁盘文件项工厂 DiskFileItemFactory factory = new DiskFileItemFactory(); ServletFileUpload fileUpload = new ServletFileUpload(factory); // 解析request对象 List<FileItem> list = fileUpload.parseRequest(request); // 遍历 for (FileItem fileItem : list) { // 判断文件项是普通字段,仍是上传的文件 if (fileItem.isFormField()) { } else { // 上传文件项 // 获取到上传文件的名称 String filename = fileItem.getName(); //解决重名文件覆盖,把文件名设置为惟一值 String uuid = UUID.randomUUID().ToString.replace("-",""); filename = uuid + filename; // 上传文件 fileItem.write(new File(file, filename)); //删除临时文件 fileItem.delete(); } } return "success"; }
SpringMVC框架提供了MultipartFile对象,该对象表示上传的文件
注意:形参变量名称必须和前端表单<input type="file" name="upload"/>
的 name属性名称相同。
与上面的第三方工具比较的优点:
1.不须要引入jar包,减小依赖
2.不须要再解析request,springMVC封装好了,在前端控制器中调用文件解析器对象来帮助解析。
3.代码简洁,干净。
原理
代碼們:
jsp
<form action="user/fileupload" method="post" enctype="multipart/form-data"> 选择文件:<input type="file" name="upload"/><br/> <input type="submit" value="上传文件"/> </form>
springmvc.xml
<!-- 配置文件解析器对象,要求id名称必须是multipartResolver --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="maxUploadSize" value="10485760"/> </bean>
controller.java
@RequestMapping(value = "/fileupload2") public String fileupload2(HttpServletRequest request, MultipartFile upload) throws Exception { System.out.println("SpringMVC方式的文件上传..."); // 先获取到要上传的文件目录 String path = request.getSession().getServletContext().getRealPath("/uploads"); // 建立File对象,一会向该路径下上传文件 File file = new File(path); // 判断路径是否存在,若是不存在,建立该路径 if (!file.exists()) { file.mkdirs(); } // 获取到上传文件的名称 String filename = upload.getOriginalFilename(); String uuid = UUID.randomUUID().toString().replaceAll("-", "").toUpperCase(); // 把文件的名称惟一化 filename = uuid + "_" + filename; // 上传文件 upload.transferTo(new File(file, filename)); return "success"; }
在实际开发中,爲了提高模塊功能的性能會單獨的將一臺服務器或多臺做爲集群服務器來延展加强功能來服務更多的用戶。 例如: 应用服务器:负责部署咱们的应用 数据库服务器:运行咱们的数据库 缓存和消息服务器:负责处理大并发访问的缓存和消息 文件服务器:负责存储用户上传文件的服务器。
1.引入依賴jar包
pom.xml
<dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-core</artifactId> <version>1.18.1</version> </dependency> <dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-client</artifactId> <version>1.18.1</version> </dependency>
2.index.jsp
<h3>跨服务器的文件上传</h3> <form action="user/fileupload3" method="post" enctype="multipart/form-data"> 选择文件:<input type="file" name="upload"/><br/> <input type="submit" value="上传文件"/> </form>
3.controller.java
本地文件對象創建改變為服务資源器對象,由服務器資源對象來進行文件書寫。
@RequestMapping(value = "/fileupload3") public String fileupload3(HttpServletRequest request, MultipartFile upload) throws Exception { System.out.println("SpringMVC跨服务器文件上传..."); // 定义图片服务器的请求路径 String path = "http://localhost:9090/springmvc_day02_03fileService_war/uploads/"; // 获取到上传文件的名称 String filename = upload.getOriginalFilename(); String uuid = UUID.randomUUID().toString().replaceAll("-", "").toUpperCase(); // 把文件的名称惟一化 filename = uuid + "_" + filename; // 向图片服务器上传文件 // 建立客户端对象 Client client = Client.create(); // 链接图片服务器 WebResource webResource = client.resource(path + filename); // 上传文件 webResource.put(upload.getBytes()); return "success"; }
系统中异常包括两类:预期异常和运行时异常 RuntimeException,前者经过捕获异常从而获取异常信息, 后者主要经过规范代码开发、测试经过手段减小运行时异常的发生。 系统的 dao、service、controller 出现都经过 throws Exception 向上抛出,最后由 springmvc 前端 控制器交由异常处理器进行异常处理
public class customException extends Exception { //消息对象 private String message; //构造函数 public customException(String message) { this.message = message; } //get方法 public String getMessage() { return message; } }
<%@ 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>执行失败</title></head> <body> 执行失败! ${message } </body> </html>
public class customExceptionResolver implements HandlerExceptionResolver { @Override public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) { e.printStackTrace(); customException customException = null; if (e instanceof customException) { customException = (customException) e; } else { customException = new customException("系统错误,请与系统管理 员联系!"); } ModelAndView modelAndView = new ModelAndView(); modelAndView.addObject("message", customException.getMessage()); modelAndView.setViewName("error"); return modelAndView; } }
<!-- 配置自定义异常处理器 --> <bean id="handlerExceptionResolver" class="cn.itcast.eResolver.customExceptionResolver"/>
原理:全部的異常都會經過前端控制器,那麽在前端控制器作人爲的異常攔截(處理)將可識別的異常情況s,通過手寫代碼設置特別響應s
這樣就不會給用戶看一坨Tomcat的報錯了。
customException類,主要功能是獲取xxx.jsp頁面抛出的異常,在異常被捕獲的時候,并將異常信息傳遞給customExceptionResolver異常處理器,由異常處理器保存異常信息至modelAndView對象並跳轉頁面至error.jsp
Spring MVC 的处理器拦截器相似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理和后处理,也就是AOP思想具體應用的一種
拦截器链(Interceptor Chain)。拦截器链就是将拦截器按必定的顺 序联结成一条链。
在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其以前定义的顺序被调用。
过滤器是 servlet 规范中的一部分,任何 java web 工程均可以使用。 拦截器是 SpringMVC 框架本身的,只有使用了 SpringMVC 框架的工程才能用。 过滤器在 url-pattern 中配置了/*以后,能够对全部要访问的资源拦截。 拦截器它是只会拦截访问請求——控制器方法,若是访问的是 jsp,html,css,image 或者 js 是不会进行拦 截的
自定义拦截器, 要求必须实现:HandlerInterceptor 接口
public class HandlerInterceptorDemo1 implements HandlerInterceptor { /** * 预处理回调方法,实现处理器的预处理(如检查登录),第三个参数为响应的处理器,自定义Controller * 返回值:true表示继续流程(如调用下一个拦截器或处理器);false表示流程中断(如登陆检查失败), * 不会继续调用其余的拦截器或处理器,此时咱们须要经过response来产生响应; */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("拦截器preHandle拦截方法执行了,但放行了"); //request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request,response); return true; } /** * 后处理回调方法,实现处理器的后处理(但在渲染视图以前),此时咱们能够经过modelAndView(模型和视图对象) * 对模型数据进行处理或对视图进行处理,modelAndView也可能为null。 */ @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("拦截器postHandle后处理方法执行了,没法拦截,但可手动跳转"); } /** * 整个请求处理完毕回调方法,即在视图渲染完毕时回调,如性能监控中咱们能够在此记录结束时间并输出消耗时间, * 还能够进行一些资源清理,相似于try-catch-finally中的finally,但仅调用处理器执行链中 */ @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("afterCompletion (final)方法执行了"); } }
<!-- 配置拦截器 --> <mvc:interceptors> <mvc:interceptor> <!-- 拦截范围:全部controller --> <mvc:mapping path="/**"/> <mvc:exclude-mapping path=""/> <bean id="handlerInterceptorDemo1" class="cn.itcast.interceptor.HandlerInterceptorDemo1"></bean> </mvc:interceptor> </mvc:interceptors>
<html> <body> <h2>Hello World!</h2> <a href="user/testInterceptor">Sout</a> </body> </html>
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <h2>You are Success!!</h2> <% System.out.println("success.jsp页面渲染了");%> </body> </html>
特殊状况:
当preHandle方法中写了手动跳转页面则不继续执行postHandle方法,即使写了return true;但仍会继续执行afterCompletion
实例:
HandlerInterceptorDemo1彻底实现类.java
@Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("拦截器preHandle拦截方法执行了,但放行了"); request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request,response); return true; }
success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <h2>You are Success!!</h2> <% System.out.println("suceesss.jsp页面渲染了");%> </body> </html>
測試执行结果:
preHandle 拦截器拦截了
suceesss.jsp页面渲染了
afterCompletion 方法执行了
按照springMVC中<mvc:interceptor />
再配置多個,寫同名同路經的彻底實現類便可。
如何调用: 按拦截器定义顺序调用 什么时候调用: 只要配置了都会调用 有什么用: 若是程序员决定该拦截器对请求进行拦截处理后还要调用其余的拦截器,或者是业务处理器去进行处理,则返回 true。 若是程序员决定不须要再调用其余的组件去处理请求,则返回 false. [注:false对客户端来讲就是空白页面]
测试執行结果
拦截器1preHandle
拦截器2preHandle
controller
拦截器2postHandle
拦截器1postHandle
success.jsp渲染
拦截器2afterCompletion
拦截器1afterCompletion
<!ELEMENT web-app (icon?, display-name?, description?, distributable?, context-param*, filter*, filter-mapping*, listener*, servlet*,servlet-mapping*, session-config?, mime-mapping*, welcome-file-list?,error-page*, taglib*, resource-env-ref*, resource-ref*, security-constraint*, login-config?, security-role*, env-entry*, ejb-ref*, ejb-local-ref*)>
<?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"> <display-name>MyBatis_06_ssm</display-name> <!-- Spring默認配置 --> <!-- needed for ContextLoaderListener --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <!-- Bootstraps the root web application context before servlet initialization --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- SpringMVC前端控制器(核心) --> <!-- The front controller of this Spring Web application, responsible for handling all application requests --> <servlet> <servlet-name>spring</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <!-- 設置前端控制器控制範圍 --> <!-- Map all requests to the DispatcherServlet for handling --> <servlet-mapping> <servlet-name>spring</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
提示:若是在eclipse中安裝了Spring IDE插件則這裏的Spring和SpringMVC標簽都直接Alt+/
選擇#ContextLoaderListener
#dispatcherservlet
便可添加
注意:關於SpringMVC中的<init-param/>
以及Spring<context-param/>
SpringMVC的配置文件路徑能够根據默認約定:
使用前端控制器(servlet)的servlet-name,"/WEB-INF/"+servlet-name+"-servlet.xml"
也就是/WEB-INF/spring-servlet.xml
。
Spring的配置文件若沒有通過context-param标签指定,則其param-name值默认是contextConfigLocation,param-value默认是/WEB-INF/applicationContext.xml
。
通常來説,Spring的配置文件都是在類路徑下
也就是须要寫明param-value=classpath:applicationContext.xml
以及配置spring,必需要有listener标签。