1.什么是springmvc
1).轻量级的框架
2).基于spring的IOC 和 AOP进行封装
3).基于Servlet进行封装
4).实现了mvc设计思想的框架
2.springmvc的执行流程图
1).浏览器发送http请求
2).前端控制器DispatcherServlet负责接收所有的请求
3).前端控制器调度处理器映射器HandlerMapping处理请求映射
4).处理器映射器返回HandlerExecutionChain(处理器执行链)
5).前端控制器调度HandlerAdapter(处理器适配器)执行处理器执行链条
6).处理器适配器调度执行处理具体请求的后端控制器
7).返回ModelAndView(模型视图)给前端控制器
8).前端控制器调度ViewResolver视图解析器将逻辑视图解析成真实视图
9).视图解析器将真实视图返回给前端控制器
10).前端控制器调度视图渲染工具渲染视图
11).将渲染好的视图响应给浏览器
springmvc核心组成部分
①: DispatcherServlet 中央处理器或者前端控制器(总控) ②: HandlerMapping 处理器映射器(负责将请求url和处理器进行关联) ③: HandlerAdapter 处理器适配(负责调度执行后端处理器或者控制器) ④: ViewResover 视图解析器(负责将逻辑视图解析成真实视图)
3.基础结构
1.控制层的书写FirstController
package com.jbit.controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractController;
import org.springframework.web.servlet.mvc.Controller;
/**
* 控制器
* @author Administrator
*
*/
public class FirstController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
System.out.println("处理了第一个springmvc请求");
return new ModelAndView("show");
}
}
SecondController
package com.jbit.controller;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.HttpRequestHandler;
/**
* 控制器
* @author Administrator
*
*/
public class SecondController implements HttpRequestHandler {
@Override
public void handleRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("执行了SecondController的处理请求的方法");
request.getRequestDispatcher("/WEB-INF/jsp/show.jsp").forward(request, response);
}
}
2.web.xml配置
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
metadata-complete="false">
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 通过初始化参数来指定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-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
3.springmvc.xml配置
<!-- 1.配置处理器映射器 -->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/myFirst">firstController</prop>
<prop key="/helloFirst">firstController</prop>
<prop key="/mySecond">secondController</prop>
</props>
</property>
</bean>
<!-- 2.配置处理器适配器 -->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>
<bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"></bean>
<!-- 备注: 前两个默认在Dispatcher.properties文件中已经配置好了,可以不用配置,如果人为配置了就会覆盖配置文件中的信息 -->
<!-- 3.配置处理具体请求的控制器 -->
<bean id="firstController" name="/first" class="com.jbit.controller.FirstController"></bean>
<bean id="secondController" name="/second" class="com.jbit.controller.SecondController"></bean>
<!-- 4.配置视图解析器
使用: 前缀 + 控制器中返回的视图名称 + 后缀来准确定位具体的视图
/WEB-INF/jsp/show.jsp
-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
4.参数和转换器
1.基于注解的springmvc
1).配置基于注解的处理器映射器
2).配置基于注解的处理器适配器
以上两步默认已经在DispatcherServlet.properties中配置,可以配置
配置的基于注解的处理器映射器和处理器适配器可以通过如下标签取代
<mvc:annotation-driven/>
并且该标签具备更多其他附加功能: 比如自定义的类型转换器
3).配置视图解析器
4).自定义控制类和处理请求的方法添加如下注解
@Controller: 让IOC容器来创建并管理处理具体请求的控制器对象;
@RequestMapping("/url"): 用于配置控制器类以及处理方法的请求映射地址;
5).添加注解扫描的基础包
<context:component-scan base-package="com.jbit"></context:component-scan>
6).发送请求测试
springmvc中请求参数的发送和获取
在springmvc中通过编码过滤器的方式统一设置请求和响应的编码格式
<!-- 配置项目的编码过滤器 -->
<filter>
<filter-name>EncodingFilter</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>
<!-- 通过初始化参数的形式将request和response对象的编码强制统一为同一编码 -->
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>EncodingFilter</filter-name>
<!-- 备注: 让该项目的所有请求统一经过编码过滤器过滤处理 -->
<url-pattern>*</url-pattern>
</filter-mapping>
1).在处理请求的方法中直接声明HttpServletRequest类型形式参数来获取
2).在处理请求的方法中直接声明和请求参数名称相同的形式参数接收要求: 形式参数的名称必须和视图层发送请求的参数名称要相同; 如果请求参数的名称和接收数据的形式参数名称不同 也可以使用 @RequestParam()注解来标记参数,使用 注解标记参数要求注解的value属性值必须和请求参数名称相同;
3).将多个请求参数封装成实体对象,在处理方法的形式参数中直接使用对象接收要求: pojo的属性名称必须和请求参数的名称一致
4).批量操作的时候: 使用数组来接收请求参数要求: 多个请求参数的名称相同
5).批量增加: List类型集合接收请求参数①: 将批量操作的数据存放到List集合,将集合设计成一个pojo的属性 ②: 表单名称设置方式: pojo的集合类型的属性名称[下标].T类的属性名;
6).批量操作: Map<K,V>①: 将批量操作的数据存放Map<K,V>集合,将map集合设计成一个pojo的属性 ②: 表单名称设置方式: pojo的Map集合类型的属性名称.['key'].V类的属性名;
7).一个pojo A类内包含了另一个pojo B类型的属性①: 直接声明A类的形式参数接收数据 ②: 表单名称设置方式: A类内部的B类型的属性名称.B类的属性名;
8).自定义类型转换器来转换项目需求的特殊类型的参数 代码如下
package com.jbit.controller;
import java.util.List;
import java.util.Map;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import com.jbit.entity.Condition;
import com.jbit.entity.Data;
import com.jbit.entity.PostInfo;
import com.jbit.entity.User;
/**
* 处理和用户信息相关的请求的控制器
* @author Administrator
*
*/
@Controller
@RequestMapping(value = "/user")
public class UserController {
//可以编写任意的处理请求的方法
// @RequestMapping(value = "/first")
// public String first(HttpServletRequest request) {
// System.out.println("执行了UserController类的first()方法!");
// //获取请求参数
// String data = request.getParameter("data");
// System.out.println("接收到的请求参数是: " + data);
// return "show";
// }
@RequestMapping(value = "/first")
public String first(@RequestParam(value = "data2",required = true,defaultValue = "王八蛋")String data1) {
System.out.println("执行了UserController类的first()方法!");
System.out.println("接收到的请求参数是: " + data1);
return "show";
}
@RequestMapping(value = "/second")
public String second() {
System.out.println("执行了UserController类的second()方法!");
return "show";
}
@RequestMapping(value = "/test1")
public String test1(Condition condition) {
System.out.println("接收到的查询条件是: " + condition);
return "show";
}
@RequestMapping(value = "/test2")
public String test2(int [] stuNos) {
System.out.println("接收到的学号是: ");
for (int i : stuNos) {
System.out.println(i);
}
return "show";
}
@RequestMapping(value = "/test3")
public String test3(Data data) {
System.out.println("接收到的快递信息是: ");
for (PostInfo postInfo : data.getPostInfos()) {
System.out.println(postInfo);
}
System.out.println("map集合信息迭代如下: ");
for (Map.Entry<String, PostInfo> entry : data.getMap().entrySet()) {
System.out.println(entry.getKey());
System.out.println(entry.getValue());
}
return "show";
}
@RequestMapping(value = "/test4")
public String test4(Data data) {
System.out.println(data.getPostInfo());
return "show";
}
@RequestMapping(value = "/pointer")
public String pointer(User user) {
System.out.println(user);
return "show";
}
}
自定义转换器代码:
package com.jbit.converter;
import org.springframework.core.convert.converter.Converter;
import com.jbit.entity.Pointer;
/**
* 自定义的Pointer类型转换器
* @author Administrator
*
*/
public class PointerConverter implements Converter<String, Pointer> {
@Override
public Pointer convert(String source) {
System.out.println("-------------------------");
System.out.println("转换前的原始数据是: " + source);
System.out.println("-------------------------");
//source: 原始数据 --> "(x,y)"
int x = Integer.parseInt(source.substring(1,source.indexOf(",")));
int y = Integer.parseInt(source.substring(source.indexOf(",") + 1,source.indexOf(")")));
//T是目标结果对象
Pointer pointer = new Pointer(x, y);
return pointer;
}
}
5.数据的回显
- springmvc结果跳转跳转方式:
视图解析器配置的前缀 + 逻辑视图名称 + 视图解析器配置的后缀
此处的跳转是指: 从控制器处理方法到结果视图的跳转过程
1).转发到指定的视图 (默认) return "视图名";
2).重定向到指定视图 return "redirect:视图名称.jsp";
3).转发到指定的控制器处理方法 return "forward:控制器url名称";
4).重定向到指定的控制器处理方法 return "redirect:控制器url名称"; - springmvc中控制器中的数据回显到视图1).通过在处理方法中return ModelAndView的方式实现回显
2).通过设置处理方法的Model类型的形式参数进行数据回显
3).通过设置处理方法的ModelMap类型的形式参数进行数据回显
4).通过设置处理方法的Map类型的形式参数进行数据回显
备注: 都是将模型数据默认映射到request请求作用域中进行回显示
5).也可以使用Servlet API 将数据显示保存到request 或者 session
备注: springmvc设计的时候希望在框架使用中弱化甚至消除ServletAPI@SessionAttributes(value = {"user"}) @SessionAttributes(types = {User.class}) 可以通过以上注解将指定类型数据或者指定key的回显数据保存到session域中;
- springmvc控制器中的处理请求的方法返回值类型1).ModelAndView: 返回模型视图
2).String: 返回逻辑视图的名称
3).void: 需要使用ServletApi
直接使用request 或者 response进行结果视图跳转 - springmvc中的常用注解
@Controller
@RequestMapping 该注解用于映射控制url
name属性: 用于指定映射名称
value和path属性都是用于指定控制器的访问url,而且都是String[],同一个控制器可以指定多个url
value = {
"",
"/test",
"/test*",//以任意字符开头 结尾 包含任意字符串等
"/test/*/aa", // 匹配一个层级的任意url路径
"/test/**/ss" // user/test/aasdfa/dsafgs/afgds/ss 匹配多个层级
}
method属性用于指定请求方式
默认是RequestMethod.GET
如果前台发送请求的方式后该属性配置的方式不一致则抛出异常
HttpRequestMethodNotSupportedException
params属性用于指定请求参数的名称和值的要求
params = {"data","num=2","result!=16"}
如果不满足该属性指定的请求参数格式则抛出异常
UnsatisfiedServletRequestParameterException
headers属性用户设置请求必要的请求头信息
如果不满足设置的请求头信息,则提示404,请求资源无法找到
@SessionAttributes(names={},types={}),只能标记类
该注解用于将指定key的回显数据和指定类型的回显数据保存到session作用域
@RequestAttribute: 用于标记参数,是取出request域中指定key的数据并设置给标记了该注解的参数;
@SessionAttribute: 用户标记参数,是取出session域中指定key的数据并设置给标记了该注解的参数;.
控制层代码:
package com.jbit.controller;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.servlet.ModelAndView;
import com.jbit.entity.User;
/**
* 控制器类
* @author Administrator
*
*/
@Controller
@RequestMapping("/user")
//@SessionAttributes(value = {"user"})
//@SessionAttributes(types = {User.class})
public class UserController {
/*-------------------------------------------------------------*/
//以下这个方法通常是在特定的过滤器或者拦截器中设置请求域的数据
@RequestMapping("/testRequestAttribute")
public String testRequestAttribute(HttpServletRequest request) {
request.setAttribute("req_k", "req_v");
return "forward:demo";
}
@RequestMapping("/demo")
public String testDemo(@RequestAttribute("req_k") String req_k) {
System.out.println("请求作用域中获取的数据是: " + req_k);
return "show";
}
/*-------------------------------------------------------------*/
//springmvc的@RequestMapping()
/*-------------------------------------------------------------*/
@RequestMapping(
value = {
// "",
// "/test",
// "/test*",//以任意字符开头 结尾 包含任意字符串等
// "/test/*/aa", // 匹配一个层级的任意url路径
// "/test/**/ss" // user/test/aasdfa/dsafgs/afgds/ss 匹配多个层级
"/testRequestMapping"
},
method = RequestMethod.GET,
// params = {"data","num=2","result!=16"}
headers = {"hello=aa"}
)
public String testRequestMapping() {
System.out.println("执行了testRequestMapping()方法!");
return "show";
}
/*-------------------------------------------------------------*/
@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView() {
ModelAndView mv = new ModelAndView();
mv.setViewName("show");
//在模型视图对象中保存数据到视图层回显
mv.addObject("mv_key", "mv_value");
return mv;
}
@RequestMapping("/testModel")
public String testModel(Model model) {
model.addAttribute("model_key", "model_value");
return "show";
}
@RequestMapping("/testModelMap")
public String testModelMap(ModelMap mm) {
mm.addAttribute("mm_key", "mm_value");
return "show";
}
@RequestMapping("/testMap")
public String testMap(Map<String, Object> map) {
map.put("map_key", "map_value");
map.put("user", new User("admin","123456"));
return "show";
}
@RequestMapping("/testShow")
public String testShow(HttpServletRequest request,HttpSession session) {
request.setAttribute("request_key", "request_value");
session.setAttribute("session_key", "session_value");
return "show";
}
/*-------------------------------------------------------------*/
@RequestMapping("/testDispatcherToView")
public String testDispatcherToView() {
System.out.println("执行类testDispatcherToView()方法!");
return "show";
}
@RequestMapping("/testRedirectToView")
public String testRedirectToView() {
System.out.println("执行类testRedirectToView()方法!");
return "redirect:show.jsp";
}
@RequestMapping("/testDispacherToController")
public String testDispacherToController(HttpServletRequest request) {
System.out.println("执行了testDispacherToController()方法!");
request.setAttribute("req_key", "req_value");
return "forward:test";
}
@RequestMapping("/testRedirectToController")
public String testRedirectToController(HttpServletRequest request) {
System.out.println("执行了testRedirectToController()方法!");
request.setAttribute("req_key", "req_value");
return "redirect:test";
}
@RequestMapping("/test")
public String test(HttpServletRequest request) {
System.out.println("执行了test()方法!");
System.out.println("在test()处理方法中获取请求作用域的数据是: " + request.getAttribute("req_key"));
return "show";
}
}
回显至页面代码: