Spring MVC

Spring MVC


一 什么是MVC

  • Model : 模型层 封装数据和业务逻辑
  • View : 视图层 用来收集数据和 显示数据
  • Controller : 控制层 用来结合Model 和 View 的控制流程
    传统的项目 MVC 组成 : javaBean + Servlet + html(jsp、css等)

二 Spring Web MVC

  • Spring 提供了一个 Web MVC 框架,便于开发MVC结构 的 Java Web 程序
  • Spring MVC 框架控制器为 DispatcherServlet,它负责接受请求,然后将请求分发到不同的处理器进行业务处理,最后由控制器完成转发动作

1、Spring Web MVC 的核心组件

  • DispacherServlet 控制器层 程序的入口 (Web.xml里面配置)
  • HandlerMapping 控制器层 请求派发
  • Controller 控制器层 处理核心流程
  • ModelAndView 模型和视图层 封装数据视图信息
  • ViewResolver 视图处理器层
    Spring MVC 图例
request
response
View
DispacherServlet
HandlerMapping
contorller
ModelAndView
ViewResolver
View

2、Spring MVC 项目的建立

① 非注解形式SpringMVC建立
  • 建立一个Web 项目

  • 导入相关jar包

  • 在 web.xml 中配置 DispacherServlet

    	<?xml version="1.0" encoding="UTF-8"?>
    <web-app 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_4_0.xsd"
             version="4.0">
             
        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:applicationContext.xml</param-value>
        </context-param>
        
        <servlet>
            <servlet-name>SpringMvc</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>classpath:applicationContext.xml</param-value>
            </init-param>
            <load-on-startup>1</load-on-startup>
        </servlet>
        
        <servlet-mapping>
            <servlet-name>SpringMvc</servlet-name>
            <url-pattern>*.do</url-pattern>
        </servlet-mapping>
    </web-app>
    
  • 在 Spring 配置文件(applicationContext.xml)中配置HandlerMapping 的实现类 SimpleUrlHandlerMapping

        <bean id="handlerMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <props>
                <prop key="/hello.do">helloController</prop>
            </props>
        </property>
    </bean>
    
  • 写一个类,实现Controller 接口,重写方法handleRequest,并返回会ModelAndView对象,之后在Spring 配置文件中配置控制器类
    实现Controller 接口 类:

    package com.test.controller;
    
    import org.springframework.web.servlet.ModelAndView;
    import org.springframework.web.servlet.mvc.Controller;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    public class HelloController implements Controller {
        @Override
        public ModelAndView handleRequest(HttpServletRequest httpServletRequest,
                                          HttpServletResponse httpServletResponse) throws Exception {
            ModelAndView mav = new ModelAndView();
            mav.setViewName("hello");
            return mav;
        }
    }
    

    配置控制器类:

    <bean id="helloController" class="com.test.controller.HelloController"/>
    
  • 在Spring 配置文件中配置 ViewResolver

    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
    
② 注解形式SpringMVC建立
  • 建立一个Web 项目
  • 导入相关jar包
  • 在 web.xml 中配置 DispacherServlet
    	<?xml version="1.0" encoding="UTF-8"?>
    <web-app 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_4_0.xsd"
             version="4.0">
             
        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:applicationContext.xml</param-value>
        </context-param>
        
        <servlet>
            <servlet-name>SpringMvc</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>classpath:applicationContext.xml</param-value>
            </init-param>
            <load-on-startup>1</load-on-startup>
        </servlet>
        
        <servlet-mapping>
            <servlet-name>SpringMvc</servlet-name>
            <url-pattern>*.do</url-pattern>
        </servlet-mapping>
    </web-app>
    
  • 配置Spring 配置文件(applicationContext.xml)开启组件扫描, 开启标注模式的mvc(内置了更高级的HandlerMapping 并且要结合@RequestMapping(“地址”))使用
    <!--开启组件扫描-->
    <context:component-scan base-package="com.test"/>
    <!--开启标注模式的MVC-->
    <mvc:annotation-driven />
    
  • 写一个类,标注上@Controller注解(方法名,返回值,参数没有限制),类内部的方法要加上
    package com.test.controller;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    @Controller
    public class HelloController{
        @RequestMapping("/hello.do")
        public String hello(){
            return "hello";
        }
    }
    
  • 在Spring 配置文件中配置 ViewResolver
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
    

3、控制器中参数的接受

① 直接使用HttpServletRequest
@RequestMapping("/register.do")
public String getHello(HttpServletRequest httpServletRequest){
    String name = httpServletRequest.getParameter("name");
    String password = httpServletRequest.getParameter("password");
    String money = httpServletRequest.getParameter("money");
    System.out.println(name+" "+password+" "+money);
    return "register";
}
② 可以直接在,控制器方法上 写页面上对应的 参数名字,作为参数

参数接受代码:

@RequestMapping("/register2.do")
public String getHello(String name, String password, String money){
    System.out.println(name+" "+password+" "+money);
    return "register";
}

如果参数名无法保持一致,可以在参数前加上@RequestParam(“参数”)标注的形式,代码如下:
参数接受代码:

@RequestMapping("/register2.do")
public String getHello(String name, @RequestParam("password") String pwd, String money){
    System.out.println(name+" "+pwd+" "+money);
    return "register";
}
③ 使用对象 直接接受参数

要求对象中的属性 和 页面参数必须一一对应!!!
参数接受代码:

@RequestMapping("/register4.do")
public String getHello3(BankAccount bankAccount){
    System.out.println(bankAccount);
    return "register";
}

bean 实体类代码:

package com.test.bean;

public class BankAccount {
    private int id;
    private String name;
    private String password;
    private double money;

    public BankAccount() {
    }

    public BankAccount(int id, String name, String password, double money) {
        this.id = id;
        this.name = name;
        this.password = password;
        this.money = money;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }

    @Override
    public String toString() {
        return "BankAccount{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", password='" + password + '\'' +
                ", money=" + money +
                '}';
    }

前端代码:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h3>银行开户</h3>
    <form action="${pageContext.request.contextPath}/register4.do">
        名字:
        <input type="text" name="name"> <br>
        密码:
        <input type="password" name="password"> <br>
        钱数:
        <input type="text" name="money"> <br>
        <input type="submit" value="开户">
    </form>
</body>
</html>

4、控制器向页面传递参数

① 直接使用HttpServletRequest
@RequestMapping("/register1.do")
public String Register2(String name, String password, String money, HttpServletRequest request) {
	request.setAttribute("name", name);
	request.setAttribute("password", password);
	return "login";
②使用@ModelAttribute 可以 对控制器的参数进行传递

@ModelAttribute(“account”) 相当于request.setAttribute(“account”, account);

@RequestMapping("/register2.do")
public String Register3(@ModelAttribute("account")BankAccount bankAccount) {
	System.out.println(bankAccount);
	return "login";
}
③使用ModelAndView 控制器返回 ModelAndView
@RequestMapping("/register4.do")
public ModelAndView Register4(BankAccount bankAcceount) {
	System.out.println(bankAccount);
	ModelAndView mav = new ModelAndView();
	mav.setViewName("login");
	mav.getModel().put("account", bankAccount);
	return mav;
}
④使用ModelMap 对象(控制器参数是ModelMap)
@RequestMapping("/register5.do")
public String Register5(BankAccount bankAccount, ModelMap modelMap) {
	System.out.println(bankAccount);
	modelMap.addAttribute("account", bankAccount);
	// modelMap.put("account", bankAccount);
	return "login";
}
⑤使用Model 类型的参数 传递数据
@RequestMapping("/register6.do")
public String Register6(BankAccount bankAccount, Model model) {
	System.out.println(bankAccount);
	model.addAttribute("account", bankAccount);
	return "login";
}

5、转发和重定向

① 通过request 获取
② 在控制器中,直接使用HttpSession 获取

6、转发和重定向

①转发

默认就是转发 控制器无论返回的是一个字符串,还是一个ModelAndView,return “login”; 转发到/WEB-INF/login.jsp,默认路径是项目

② 重定向
  • 使用 return “redirect:login”; 发起重定向 获取到的是相对servlet 路径,就是使用绝对路径“/”

    @RequestMapping("/register7.do")
    public String Register7(BankAccount bankAccount, HttpSession session, HttpServletRequest request) {
    	System.out.println(bankAccount+"  register7.do");
    	request.setAttribute("account", bankAccount);
    	session.setAttribute("account", bankAccount);
    	return "redirect:/toRegister.do";
    }
    
  • 使用RedirectView 来完成重定向

    @RequestMapping("/register8.do")
    public ModelAndView Register8(BankAccount bankAccount, HttpSession session, HttpServletRequest request) {
    	System.out.println(bankAccount+"  register8.do");
    	request.setAttribute("account", bankAccount);
    	session.setAttribute("account", bankAccount);
    	ModelAndView mav = new ModelAndView();
    	// 获取项目路径
    	String contextPath = session.getServletContext().getContextPath();
    	// 使用RedirectView 必须手动加上项目路径
    	RedirectView redirectView = new RedirectView(contextPath + "/register6.do");
    	mav.setView(redirectView);
    	return mav;
    	
    }
    

二者区别:

  • 在效率上,转发(forward)>重定向(redirect)
  • 显示上,重定向显示新的URL,转发的地址不变
  • 数据上,转发共享数据,重定向不行
  • 请求次数,转发1次,重定向2次

7、拦截器

  • 作用 :
    可以在 HandlerMapping 组件进行拦截 可以实现权限认证 登录检查
  • 实现:
    实现 HandlerInterceptor 接口
    • preHandle 控制器点用之前
    • postHandle 控制器调用之后, 视图处理之前
    • asterHandle 视图处理之前,相应之后
      代码实现:
    public class UserActionInterceptor implements HandlerInterceptor {
    
    	@Override
    	public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
    			throws Exception {
    		    System.out.println("user action  afterCompletion ....");
    
    	}
    
    	@Override
    	public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, 
    			   Object arg2, ModelAndView arg3)
    			throws Exception {
    		 System.out.println("user action  postHandle ....");
    
    	}
    
    	@Override
    	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, 
    			Object method) throws Exception {
    		System.out.println("user action  preHandle ....:");
    		//  判定用户是否登录 登录就放行 不登录返回到登录页面 
    		Object  name = request.getSession().getAttribute("name");
    		if(name == null){
    			 response.sendRedirect("/spring-mvc-day06/user/toLogin.do");
    		     return false;	
    		}else{
    		     return true;
    		}     
    	}
    
    }
    
    配置代码:
    <!-- 配置拦截器  -->
    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/user/*" />                
            <!-- 不拦截的  -->
            <mvc:exclude-mapping path="/user/toLogin.do"/> 
            <mvc:exclude-mapping path="/user/login.do"/>     
            <bean class="com.test.interceptor.UserActionInterceptor"></bean>
        </mvc:interceptor>
    </mvc:interceptors>
    

8、多拦截器

  • preHandle 是按照配置的顺序 顺序执行
  • postHandle asterHandle 和配置的顺序相反

9、异常处理

  • 处理方式1:返回自定义异常名称,处理全部Controller 的异常
    使用 Spring 提供的SimpleMappingExceptionResolve
    配置

    <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
       <property name="exceptionMappings" >
           <props>
               <prop key="java.lang.Exception">自定义异常名称1</prop>
               <prop key="java.lang.NullPointerException">自定义异常名称2</prop>
           </props>
       </property>
    </bean>
    
  • 处理方式2:自定义异常处理器,处理全部Controller 的异常
    配置

    <bean  class="com.xdl.exception.reslover.MyExceptionResolver">
    
    </bean>
    

    实现

    @Controller
    public class MyExceptionResolver implements HandlerExceptionResolver {
    
        @Override
        public ModelAndView resolveException(HttpServletRequest request, 
                HttpServletResponse response, Object method, Exception e) {
            ModelAndView mav = new ModelAndView();
            if(e instanceof NullPointerException){
                mav.setViewName("error2");
            }else if(e instanceof Exception){
                mav.setViewName("error1");
            }
            return mav;
        }
    }
    
    
  • 处理方式3 :使用@ExceptionHandler 注解实现异常处理,处理指定Controller 的异常
    实现

    @ExceptionHandler
    public String execute(HttpServletRequest request,Exception e){
        if(e instanceof RuntimeException){
            return "error3";
        }else {
            return "error4";
       }
    }
    
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值