SpringMvc-01
springmvc环境搭建与常用注解
一、 什么叫 MVC?
模型-视图-控制器(MVC) 是一个众所周知的以设计界面应用程序为基础 的设计思想。 它主要通过分离模型、 视图及控制器在应用程序中的角色将业务 逻辑从界面中解耦。 通常, 模型负责封装应用程序数据在视图层展示。 视图仅 仅只是展示这些数据, 不包含任何业务逻辑。 控制器负责接收来自用户的请求, 并调用后台服务(service 或者 dao) 来处理业务逻辑。 处理后, 后台业务层 可能会返回了一些数据在视图层展示。 控制器收集这些数据及准备模型在视图 层展示。 MVC 模式的核心思想是将业务逻辑从界面中分离出来, 允许它们单独 改变而不会相互影响。
二、 常见 MVC 框架比较
运行性能上: Jsp+servlet>struts1>spring mvc>struts2+freemarker>struts2,ognl, 值栈。
开发效率上,基本正好相反。
值得强调的是, spring mvc 开发效率和 struts2 不相上下, 但从目前来看, spring mvc 的流行度已远远超过 struts2。 Struts2 的性能低的原因是因为 OGNL(一种表达式语言, 通过它简单一致 的表达式语法, 可以存取对象的任意属性, 调用对象的方法, 结合 struts2 框架使用)和值栈(简单理解为存放 struts2 action 的堆栈) 造成的。 所以, 如果系统并发量高, 可以使用 freemaker 进行显示, 而不是采用 OGNL 和值栈。 这样, 在性能上会有相当大得提高。
三、 Spring MVC 是什么
Spring MVC 是 Spring 家族中的一个 web 成员, 它是一种基于 Java 的实 现了 Web MVC 设计思想的请求驱动类型的轻量级 Web 框架, 即使用了 MVC 架构模式的思想, 将 web 层进行职责解耦, 基于请求驱动指的就是使用请求-响应 模型, 框架的目的就是帮助我们简化开发, Spring MVC 也是要简化我们日常 Web 开发的。 Spring MVC 是服务到工作者思想的实现。
前端控制器是DispatcherServlet;
应用控制器拆为处理器映射器(Handler Mapping)进行处理器管理和
视图解析器(View Resolver)进行视图管理;
支持本地化/国际化(Locale) 解析及文件上传等;
提供了非常灵活的数据验证、 格式化和数据绑定机制; 提供了强大的约定大于配置(惯例优先原则) 的契约式编程支持。
四、 Spring MVC 能帮我们做什么
1. 让我们能非常简单的设计出干净的 Web 层;
2. 进行更简洁的 Web 层的开发;
3. 天生与 Spring 框架集成(如 IoC 容器、 AOP 等);
4. 提供强大的约定大于配置的契约式编程支持;
5. 能简单的进行 Web 层的单元测试;
6. 支持灵活的 URL 到页面控制器的映射;
7. 非常容易与其他视图技术集成, 如 Velocity、 FreeMarker 等等, 因为模型 数据不放在特定的 API 里, 而是放在一个 Model 里(Map 数据结构实现, 因 此很容易被其他框架使用);
8. 非常灵活的数据验证、 格式化和数据绑定机制, 能使用任何对象进行数据 绑定, 不必实现特定框架的 API;
9. 支持灵活的本地化等解析;
10. 更加简单的异常处理;
11. 对静态资源的支持;
12. 支持 Restful 风格。
五、 Spring MVC 架构 1. Spring MVC 请求处理流程分析
Spring MVC 框架也是一个基于请求驱动的 Web 框架, 并且使用了前端控制 器模式(是用来提供一个集中的请求处理机制, 所有的请求都将由一个单一的 处理程序处理来进行设计, 再根据请求映射规则分发给相应的页面控制器(动 作/处理器) 进行处理。
首先让我们整体看一下 Spring MVC 处理请求的流程:
具体执行步骤如下:
1、 首先用户发送请求,请求被 SpringMvc 前端控制器(DispatherServlet) 捕获;
2、 前端控制器(DispatherServlet)对请求 URL 解析获取请求 URI,根据 URI, 调用 HandlerMapping;
3、 前端控制器(DispatherServlet)获得返回的 HandlerExecutionChain(包括 Handler 对象以及 Handler 对象对应的拦截器) ;
4、 DispatcherServlet 根据获得的 HandlerExecutionChain, 选择一个合适的 HandlerAdapter。 (附注: 如果成功获得 HandlerAdapter 后, 此时将开始 执行拦截器的 preHandler(...)方法) ;
5、 HandlerAdapter 根据请求的 Handler 适配并执行对应的 Handler; HandlerAdapter(提取 Request 中的模型数据, 填充 Handler 入参, 开始执行 Handler(Controller)。 在填充 Handler 的入参过程中, 根据配置, Spring 将做 一些额外的工作:
HttpMessageConveter: 将请求消息(如 Json、 xml 等数据) 转换成一个 对象, 将对象转换为指定的响应信息。
数据转换: 对请求消息进行数据转换。 如 String 转换成 Integer、 Double 等
数据格式化: 对请求消息进行数据格式化。 如将字符串转换成格式化数字 或格式化日期等
数据验证: 验证数据的有效性(长度、 格式等) , 验证结果存储到 BindingResult 或 Error 中)
6、 Handler 执行完毕, 返回一个 ModelAndView(即模型和视图)给 HandlerAdaptor
7、 HandlerAdaptor 适配器将执行结果 ModelAndView 返回给前端控制器。
8、 前端控制器接收到 ModelAndView 后, 请求对应的视图解析器。
9、 视图解析器解析 ModelAndView 后返回对应 View;
10、 渲染视图并返回渲染后的视图给前端控制器。
11、 最终前端控制器将渲染后的页面响应给用户或客户端
2. Spring MVC 核心架构图
3.Spring MVC 优势
1、 清晰的角色划分: 前端控制器(DispatcherServlet) 、 请求到处理器映射(HandlerMapping) 、 处理器适配器(HandlerAdapter) 、 视图解析器(ViewResolver) 、 处理器或页面控制器(Controller) 、 验证器 ( Validator) 、 命令对象(Command 请求参数绑定到的对象就叫命令对象) 、 表单对象(Form Object 提供给表单展示和提交到的对象就叫表单对 象) 。
2、 分工明确, 而且扩展点相当灵活, 可以很容易扩展, 虽然几乎不需要;
3、 和 Spring 其他框架无缝集成, 是其它 Web 框架所不具备的;
4、 可适配, 通过 HandlerAdapter 可以支持任意的类作为处理器;
5、 可定制性, HandlerMapping、 ViewResolver 等能够非常简单的定制;
6、 功能强大的数据验证、 格式化、 绑定机制;
7、 利用 Spring 提供的 Mock 对象能够非常简单的进行 Web 层单元测试;
8、 本地化、 主题的解析的支持, 使我们更容易进行国际化和主题的切换。
9、 强大的 JSP 标签库, 使 JSP 编写更容易。
还有比如 RESTful(一种软件架构风格, 设计风格而不是标准, 只是提供了一组设计原则和约束条件。 它主要用于客户端和服务器交互类的软件, 目前了解即可) 风格的支持、 简单的文件上传、 约定大于配置的契约式编程支持、 基于注解的零配置支持等等。
六、 Spring Mvc 环境搭建
1.开发环境 MyEclipse + jdk1.7 + maven + jetty
2.新建 Maven webApp 建立 springmvc01 工程 并调整 web 环境 (jre、 web3.0、 java 1.7 这里不再讲解)
3.springmvc 环境 jar 包依赖
pom.xml引入依赖
4.0.0
com.shsxt
springMvc-01-huanjing
1.0-SNAPSHOT
war
springMvc-01-huanjing Maven Webapp
UTF-8
1.8
1.8
junit
junit
4.12
test
org.springframework
spring-web
4.3.2.RELEASE
org.springframework
spring-webmvc
4.3.2.RELEASE
javax.servlet
javax.servlet-api
3.0.1
springMvc-01-huanjing
org.mortbay.jetty
maven-jetty-plugin
6.1.25
10
/springMvc-01-huanjing
4.配置 web.xml (前端控制器配置)
要想启动我们的 springMvc 环境,目前对于 mvc 框架的配置还未进行。以上在 web.xml中引用了 servlet-context.xml 文件
contextConfigLocation
classpath:*.xml
org.springframework.web.context.ContextLoaderListener
char encoding filter
encodingFilter
org.springframework.web.filter.CharacterEncodingFilter
encoding
UTF-8
encodingFilter
/*
springMvc
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath:servlet-context.xml
1
springMvc
/
5. servlet-context.xml 配置
6.页面控制器的编写HelloController控制层
@Controller
public class HelloController {
@RequestMapping("hello")
public String hello(){
return "hello";
}
@RequestMapping("world")
public String world(){
return "world";
}
7.添加视图页面 在 WEB-INF 下新建 jsp 文件夹 ,并在文件加下新建 hello.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
springmvc
Hello SpringMVC01!!
8.启动 jetty 服务器 选中项目 右键 –>run as -->maven build ->goals 输入框中输入 jetty:run 即 可启动服务器
9.如果这里启动成功,浏览器(最好用强大的chrome或者火狐浏览器,程序员的最爱!!!)访问地址最终效果如下:
七、 SpringMvc 注解特性
1.@Controller 控制器定义
在 spring 3.0 中,通过@controller 标注即可将 class 定义为一个 controller 类。为 使 spring 能找到定义为 controller 的 bean,
需要在 spring-context 配置文件中增加如下 定义:
注:实际上,使用@component,也可以起到@Controller 同样的作用
2.@RequestMapping 在类前面定义,则将 url 和类绑定。
在方法前面定义,则将 url 和类的方法绑定
3.参数绑定 请求参数到处理器功能处理方法的方法参数上的绑定, 对于参数绑定非常灵活
a).基本数据类型、 字符串数据绑定
b).数组类型
c).vo 类型
d) .list 类型 新定义phone实体类,此时 user 实体需要定义 list 属性,
private List
e).set 类型 set 和 List 类似,也需要绑定在对象上,而不能直接写在 Controller 方法 的参数中。
但是,绑定 Set 数据时,必须先在 Set 对象中 add 相应的数量的模型 对象。无序存储的原因
1)user类中增加set集合
package com.shsxt.vo;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* @author Administrator
* *
/
/**
* @author Administrator
* *
/
public class User {
private int id;
private String userName;
private String userPwd;
private Set phones=new HashSet();
public User() {
phones.add(new Phone());
phones.add(new Phone());
phones.add(new Phone());
}
/*public List getPhones() {
return phones;
}
public void setPhones(List phones) {
this.phones = phones;
}*/
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserPwd() {
return userPwd;
}
public void setUserPwd(String userPwd) {
this.userPwd = userPwd;
}
public Set getPhones() {
return phones;
}
public void setPhones(Set phones) {
this.phones = phones;
}
}
2)Controller 方法DataBindController中绑定参数:
|
@RequestMapping("/dataTest6")
public void getParamsData6(User user){
System.out.println(user);
}
3)前台页面传参
表单页面
f).Map 类型数据 Map 最为灵活,它也需要绑定在对象上,而不能直接写在 Controller 方法的参数中。
private Map
g).自定义复合类型 user 实体 引用 Phone 实体
参数绑定测试
1)controller层新建DataBindController.java
/**
* 测试参数绑定
*/
@Controller
@RequestMapping("data")
public class DataBindController {
//简化版
@RequestMapping("hello")
public String hello(){
return "hello";
}
//完整版
@RequestMapping("hello02")
public ModelAndView hello02(){
ModelAndView mv =new ModelAndView();
mv.setViewName("hello");//设置页面
mv.addObject("a","shanghai ");//设置相应参数
return mv;
}
//03;接受前台参数及传值普通方式
@RequestMapping("hello03")
public String hello03(HttpServletRequest request){
String a =request.getParameter("a");
System.out.println("a:"+a);
request.setAttribute("a",a);
return "hello";
}
//利用springmvc方式传值 参数绑定
@RequestMapping("hello04")
public String hello04(Integer a, String b){
System.out.println("a"+a);
System.out.println("b"+b);
return "hello";
}
//参数绑定数组类类型参数
@RequestMapping("hello05")
public String hello05(Integer[] ids){
for(Integer id:ids){
System.out.println(id);
}
return "hello";
}
//接收 vo对象类型 传统写法
@RequestMapping("hello06")
public String hello06(HttpServletRequest request){
Integer id =Integer.valueOf(request.getParameter("id"));
String name =request.getParameter("name");
Integer age =Integer.valueOf(request.getParameter("age"));
User user =new User();
user.setId(id);
user.setName(name);
user.setAge(age);
System.out.println(user);
return "hello";
}
//参数绑定 vo类型
@RequestMapping("hello07")
public String hello07(User user){
System.out.println(user);
return "hello";
}
//默认参数 分页查询(根据注解设置默认参数)
@RequestMapping("hello08")
public String hello08(
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "10") Integer pageSize) {
System.out.println(pageNum +" = " + pageSize);
return "hello";
}
}
2)po包实体类****User类
package com.shsxt.po;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Created by xlf on 2019/7/11.
*/
public class User {
private Integer id;
private String name;
private Integer age;
private List phones = new ArrayList<>();
private Map map = new HashMap();
private Phone phone;
public Phone getPhone() {
return phone;
}
public void setPhone(Phone phone) {
this.phone = phone;
}
public Map getMap() {
return map;
}
public void setMap(Map map) {
this.map = map;
}
public List getPhones() {
return phones;
}
public void setPhones(List phones) {
this.phones = phones;
}
public Integer getId() {
return id;
}
public void setId(Integer 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;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", phones=" + phones +
", map=" + map +
", phone=" + phone +
'}';
}
}
phone类
package com.shsxt.po;
public class Phone {
private String num;
public String getNum() {
return num;
}
public void setNum(String num) {
this.num = num;
}
@Override
public String toString() {
return "Phone [num=" + num + "]";
}
}
3)****前台传参测试参数绑定
4.后台向前台传参数(作用域设定)
4.1spriingMvc****方式后台将参数加入作用域
**1)新建ParamsController控制层
/**
* 后台往前台传值
*/
@Controller
@RequestMapping("params")
@SessionAttributes({"userName"}) //利用注解userName放入session作用域
public class ParamsController {
//1.传统方式放入作用域
@RequestMapping("hello1")
public String hello1(HttpServletRequest request){
request.setAttribute("a","123");
return "hello";
}
@RequestMapping("hello2")
public String hello2(HttpServletRequest request){
request.getSession().setAttribute("a","456");
return "hello";
}
//利用springmvc向前台传值
@RequestMapping("hello3")
public ModelAndView hello3(){
ModelAndView mv =new ModelAndView();
mv.addObject("a","springmvc");
mv.addObject("userName","spring boot");
mv.setViewName("hello");
return mv;
}
//利用springmvc向前台传值利用model添加进作用域
@RequestMapping("hello4")
public String hello4(Model model){
model.addAttribute("a","model");
return "hello";
}
//利用spring传值,map形式,放入作用域
@RequestMapping("hello5")
public String hello5(Map map){
map.put("a","map");
return "hello";
}
//srpingmvc设定session作用域
@RequestMapping("hello6")
public String hello6(HttpSession session){
session.setAttribute("a", "session");
return "hello";
}
}
2)前台hello.jsp页面取值
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
springmvc
Hello SpringMVC01!!
${a}
${userName}
4.2 @SessionAttributes 用于声明 session 级别存储的属性, 放置在处理器类上(了解),
利用注解将userName放入session作用域
@Controller
@SessionAttributes({"userName"})// userName 放入 session
public class UserController {
@RequestMapping("/queryUser")
public ModelAndView queryUser(String userName){
ModelAndView mv=new ModelAndView();
mv.addObject("userName", userName);
mv.setViewName("user");
return mv;
}
}