Spring MVC
1.什么是SpringMVC?
SpringMVC(Modle View Controller)是一个用来简化web开发的mvc框架,springMVC是spring框架的一部分,它是一种软件架构思想,其核心是一个软件划分为三种不同类型的模块,分别是模型,视图和控制器,其中模型用来封装业务逻辑视图用来处理表示逻辑,控制器(处理器)用来协调模型和视图,一般用java类充当模型,使用servlet充当控制器,jsp充当视图。
使用MVC框架思想实现一个简单的计算BMI指数
1.1BMI前端html页面
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>计算BMI指数</title>
</head>
<body>
<div>
<form action="bmiservlet" method="get">
<h3>计算BMI指数</h3><br>
身高(m):<input type="text" name="height"/><br>
体重(kg):<input type="text" name="weight"/><br>
<input type="submit" value="确定">
</form>
</div>
</body>
</html>
1.2web.xml配置文件
<servlet>
<servlet-name>bmi</servlet-name>
<servlet-class>web.BMIContorl</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>bmi</servlet-name>
<url-pattern>/bmiservlet</url-pattern>
</servlet-mapping>
1.3控制层(控制器)
package web;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import service.UserService;
import service.UserServiceImpl;
public class BMIContorl extends HttpServlet{
@Override
protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
String height=req.getParameter("height");
String weight=req.getParameter("weight");
//调用业务层并返回结果
UserService us=new UserServiceImpl();
String state=us.userBmiservlet(height, weight);
//数据绑定
req.setAttribute("state",state);
//转发
req.getRequestDispatcher("WEB-INF/View.jsp").forward(req, res);
}
}
注意:WEB-INF下的页面只能由后端才能调用,前端无法直接获取。
1.4业务层(模型)
package service;
/*
* 业务层
*/
public interface UserService {
String userBmiservlet(String height,String weight);
}
package service;
/*
* 业务层
*/
public class UserServiceImpl implements UserService{
@Override
public String userBmiservlet(String height, String weight) {
//计算bmi指数
double bmi=Double.parseDouble(weight)/Math.pow(Double.parseDouble(height),2);
String state="刚刚好";
if(bmi>24){
state="过重";
}
if(bmi<22){
state="过轻";
}
return state;
}
}
1.5前端JSP页面(视图 )
<%@ 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>Insert title here</title>
</head>
<body>
你的BMI指数是:${state}
</body>
</html>
1.6执行结果
2. SpringMVC的五大组件
DispatcherServlet(前端控制器)
HandleMapping(请求地址)
Controller(处理器/控制器)
ModelAndView(处理结果和视图名·)
ViewResolver(视图解析器)
SpringMVC工作原理图
2.1web.xml配置文件
<servlet>
<servlet-name>springMvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--
DispatcherServlet在初始化时,会启动spring容器,所以知道Spring配置文件的位置,可以
通过contextConfigLocation初始化参数来指定位置
-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springMvc</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
2.2Spring-mvc.xml配置文件
<!--配置HandleMapping,目的告诉DispatherServlet的请求路径和Controller的对应关系-->
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<!--key="hello.do"请求地址;helloController对应Controller被Spring管理后的id值-->
<prop key="hello.do">helloController</prop>
</props>
</property>
</bean>
<!--配置控制层/控制器-->
<bean id="helloController" class="web.HelloWorld"/>
<!--配置视图解析器(ViewResolver),目的是告诉DispatherServlet视图名对应的视图对象,例如某个jsp-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--prefix:前缀,根据绝对路径下去找相关的视图-->
<!--suffix:后缀:根据前缀和视图名去找相关的视图文件-->
<property name="prefix" value="/WEB-INF/"/>
<property name="suffix" value=".jsp"/>
</bean>
注意:
2.3控制层(Controller(处理器/控制器))
package web;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
/*
* 控制层需要实现Controller接口
*/
public class HelloWorld implements Controller{
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
ModelAndView mav=new ModelAndView("View");
//数据绑定
request.setAttribute("result","超超最帅");
return mav;
}
}
返回视图名和结果:mav和result;
2.4JSP前端页面
<%@ 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>Insert title here</title>
</head>
<body>
hello!树先生!
${result}
</body>
</html>
2.5执行结果
在地址栏输入hello.do:
得到View.jsp页面。
2.6总结
当我们在地址栏输入hello.do时,DispatcherServlet(前端控制器)会依据HandleMapping知道请求路径和Controller的对应关系;然后DispatcherServlet(前端控制器)再去通知Controller让其返回ModelAndView视图名和结果;然后DispatcherServlet(前端控制器)再将这个视图名和结果交给ViewResolver(视图解析器),让其去拼接成一个完整的jsp页面地址;最后DispatcherServlet(前端控制器)再拿着这个地址找到对应的jsp页面,通过转发将其转发出去。
形象点来说:SpringMVC工作原理就像是一个Boss和四个职工之间的关系,四个职工有着不同的工作任务,而Boss只负责分发任务和验收成果,具体的工作过程他是不管不问的。
3.MVC注解驱动的方式
3.1web.xml配置文件
几乎不用动什么,只需把一中的classpath:spring-mvc.xml改为
classpath:spring-mvc2.xml,因为我们会创建一个新的容器。
3.2Spring-mvc2.xml
注意:配置视图解析器是省略不了的
<!--配置组件扫描-->
<context:component-scan base-package="web"/>
<!--配置MVC注解驱动-->
<mvc:annotation-driven/>
<!--配置视图解析器(ViewResolver),目的是告诉DispatherServlet视图名对应的视图对象,例如某个jsp-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/"/>
<property name="suffix" value=".jsp"/>
</bean>
3.3控制层
@Controller:用于标记这是一个控制层,Spring容器会扫描到它
@RequestMapping:用于处理地址与对象之间的依赖关系,相当于HandleMapping
package web;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
/*
* 控制层也就是控制器/处理器
*/
@Controller
@RequestMapping("user")
public class HelloWorld2{
@RequestMapping("hello.do")
public ModelAndView hello(){
return new ModelAndView("View");
}
@RequestMapping("hello2.do")
public String hello2(){
return "hello";
}
}
3.4执行结果
当我们在地址栏输入user/hello.do时会返回View.jsp页面
当我们在地址栏输入user/hello2.do时会返回hello.jsp页面
4.控制层处理多个参数的方式
4.1前端html页面
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>登录页面</title>
</head>
<body>
<div align="center">
<h2>登录</h2>
<form action="user/login10.do" method="get">
用户名:<input type="text" name="username"/>
密码:<input type="password" name="userpwd"/>
<input type="submit" value="登录">
</form>
</div>
</body>
</html>
注意:
当我们访问不同地址时只需改变此值即可
4.2方式一
DispatherServlet默认以转发形式到页面
@RequestMapping("login.do")
public String login(){
return "login";
}
4.3方式二
DispatherServlet利用java反射分析方法的结构,会将对应的请求参数赋值给响应的形参.如果请求参数和形参不一致则需要使用@RequestParam(请求参数名)接收请求参数来处理,如:public String userLogin(@RequestParam(“username”)String usernames,String userpwd)
@RequestMapping("login2.do")
public String userLogin(String username,String userpwd){
System.out.println(username+","+userpwd);
return "login";
}
4.4方式三
DispatcherServlet在调用Controller的方法前,会利用java发射机制分析方法的结构,如果发现有一个request对象,则DispatcherServlet会将request作为一个参数传递进来。
@RequestMapping("login3.do")
public String Login2(HttpServletRequest request){
String username=request.getParameter("username");
System.out.println(username);
return "login";
}
4.5方式四
适用封装成对象的方法接收请求参数,请求参数需要和bean对象中的bean属性保持一致。
将参数封装到user对象中,需要我们创建User类
package entry;
import java.io.Serializable;
public class User implements Serializable{
private static final long serialVersionUID = 1L;
String username;
String userpwd;
public String getUsername() {
return username;
}
public void setUsername(String username) {
System.out.println("测试1");
this.username = username;
}
public String getUserpwd() {
return userpwd;
}
public void setUserpwd(String userpwd) {
System.out.println("测试2");
this.userpwd = userpwd;
}
@Override
public String toString() {
return "User [username=" + username + ", userpwd=" + userpwd + "]";
}
}
@RequestMapping("login4.do")
public String Login4(User user){
System.out.println(user.getUsername()+","+user.getUserpwd());
return "login";
}
4.6方式五
将绑定的数据转发到jsp页面
@RequestMapping("login5.do")
public String Login5(User user,HttpServletRequest request){
request.setAttribute("name",user.getUsername());
return "login";
}
4.7方式六
如果返回值是ModelAndView对象,则需要使用map集合添加相关的数据, 最后将map集合转到modelAndview对象中;DispatcherServlet会将key作为绑定名,将数据绑定到request对象上。
@RequestMapping("login6.do")
public ModelAndView Login6(User user){
String name=user.getUsername();
Map<String,Object> map=new HashMap<String, Object>();
map.put("name",name);
ModelAndView mav=new ModelAndView("login",map);
return mav;
}
4.8方式七
session绑定
@RequestMapping("login7.do")
public String Login7(User user,HttpSession session){
session.setAttribute("name",user.getUsername());
return "login";
}
4.9方式八
DispatcherServlet以addAttribute的绑定名(name)作为绑定名, 将数据绑定到request对象上
@RequestMapping("login8.do")
public String Login8(User user,ModelMap model){
model.addAttribute("name",user.getUsername());
return "login";
}
4.10方式九
重定向方式一
@RequestMapping("login9.do")
public String Login9(User user){
return "redirect:index.do";
}
@RequestMapping("index.do")
public String index(){
return "index";
}
执行index.jsp页面
4.11方式十
重定向方式二
@RequestMapping("login10.do")
public ModelAndView Login10(){
//创建重定向对象RedirectView(重定向的地址)
RedirectView rd=new RedirectView("index.do");
ModelAndView mav=new ModelAndView(rd);
return mav;
}
@RequestMapping("index.do")
public String index(){
return "index";
}
与重定向方式一结果相同
4.12总结
大多数处理参数的方式都是绑定和转发,有些虽然表面没用,底层还是用的request绑定和转发的。