springMVC入门

1、MVC设计概述

MVC(Model-View-Controller)模式是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model)、视图(View)和控制器(Controller)。MVC可对程序的后期维护和扩展提供方便,也为程序某些部分的重用提供了方便。

MVC 设计模式并不是Java Web应用的专属,几乎现在所有 B/S 结构的软件都采用了MVC 设计模式:在早期的 Java Web 开发中,主要是JSP+Java Bean模式,如图所示。服务器端只有JSP页面,所有操作都在JSP页面中,严重的耦合度增加了开发的难度,对后期的维护和扩展极其不利。


 

2、Spring MVC

首先,Spring MVC框架是围绕着Dispatche Servlet工作的,这个是其核心美,其实它本质是一个Servlet,因此它可以拦截HTTP 发送过来的请求,在Servlet初始化时,Spring MVC 会根据配置,获取配置信息,从而得到统一资源标识符(URL,Uniform Resource Identifier)和处理器(Handler)之间的映射关系(Ha adlerMapping),为了使用更加灵活,且能增强功能,Spring MVC还会给处理器加入拦截器,所以还可以在处理器执行前后加入自己的代码,这样就构成了一个处理器的执行链(Handl er Execution Chain),并且根据上下文初始化视图解析器等内容,当处理器返回的时候就可可以通过视图解析器定位视图,然后将数据模型渲染到视图中,以响应用户的请求。

Spring MVC的核心在于其流程,这是使用 Spring MVC框架的基础,Spring MVCH一种基Servlet 的技术,它提供了核心控制器 DispatcherServlet 和相关的组件,并制定了松散的结构,以适应各种灵活的需求。其流程图如图所示。

具体的步骤如下:

  • 第一步:发起请求到前端控制器(Dispatcherervet)
  • 第二步:前端控制器请求HandlerMapping查找Hande可以把注解进行查找)
  • 第三步:处理器映射器HandlerMapping控制器andleHanderMapping合把请水映射为HandlerExecutionChain 对象(包含一个Handler处理器(页面控制器)对象,多个HandlerInterceptor拦截器对象),通过这种策略模式,很容易添加新的映时策略
  • 第四步:前端控制器调用处理器适配器上执行 Handiers
  • 第五步:处理器适配器HandlerAdapter将会根据适配的结渠执行Handker
  • 第六步:Handler 执行完成给适配器返回ModelAndView。
  • 第七步:处理器适配器向前端控制器返回ModelAndView(ModelAndView是 Spring MvC框架的一个底层对象,包括Model 和View)。
  • 第八步:前端控制器请求视图解析器进行视图解析(根据逻辑视图名解析成真正的视图(Jsp)),通过这种策略很容易更换其他视图技术,只更改视图解析器即可。
  • 第九步:视图解析器向前端控制器返回 View。
  • 第十步:前端控制器进行视图渲染(视图渲染将模型数据(在ModelAndView对象中)填充到 request 域)。
  • 第十一步:前端控制器向用户响应结果。

以上就是一个 Spring MVC完整的流程,它是一个松散的结构,所以可以满足各类请求的需要,为此它也实现了大部分请求所需的类库,拥有较为丰富的类库供使用,所以流程中大部分组件并不需要用户去实现。 

3、springMVC入门实例

1、创建web项目并导入jar包

2、 index.jsp页面中创建一个a标签,执行一个地址请求

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>首页</title>
  </head>
  <body>
  <h2>欢迎来到项目首页</h2>
  <h3><a href="test">请求测试</a></h3>
  </body>
</html>

zhuye.jsp页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>项目主页</title>
</head>
<body>
<h2>SpringMVC的项目主页!</h2>
</body>
</html>

3、在web.xml中配置springMVC的核心控制器DispatcherServlet,同时设置它创建的时候加载

springmvc 的核心配置文件 springmvc.xml
<?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">
    <!--配置springMVC的核心控制器-->
    <servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!--配置DispatcherServlet初始化时 加载 核心配置文件springmvc.xml-->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc.xml</param-value>
        </init-param>
        <!--配置加载的时机:非0表示在服务器启动的时候即加载-->
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

关于web.xml中的一些配置解释如下。
①contextConfigLocation:用于指定配置文件的位置。如果有多个配置文件,以逗号
隔开;如果没有指定配置文件,Spring监听器会自动查找/WEB-INF/路径下applicationContext.xml配置文件。

②ContextLoaderListener:它是Spring提供的监听器,实现了 ServleiCon接口。由它来查找 Spring 的配置文件,完成对 Spring 的初始化。

③ DispatcherServlet:它是Spring的核心控制器,其初始化属性配置用于指定spring的配置文件位置。如果没有进行初始化配置,其默认的配置文件在/WEB-INF 路径下,名称为配置的servlet-name连上-servlet.xml。例如servlet-name为dispatcher,则配置文件名称为dispatcher-servlet.xml。

④ servlet-mapping:它是 servlet拦截配置,servlet-name 需要和上面配置的servict中的servlet-name 一致。<url-pattern>是拦截指定形式的请求,例如这里配置的是“”,则会拦截所有路径型的url;如果配置的是*.do,则会拦截所有以后缀“do”结尾的请求。

4、src目录下创建核心配置文件springmvc.xml,扫描控制器的包、配置视图解析器、开启注解驱动支持(默认配置 HandlerMapping映射器 和 HandlerAdapter 适配器)

<?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:aop="http://www.springframework.org/schema/aop"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="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.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/mvc
       http://www.springframework.org/schema/mvc/spring-mvc.xsd">
    <!--扫描com.zhan.controller包中的类的@Component及同名注解,把类的对象交给IOC容器-->
    <context:component-scan base-package="com.zhan.controller"/>
    <!--配置视图解析器-->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--指定视图的位置-->
        <property name="prefix" value="/"/>
        <!--指定视图的后缀-->
        <property name="suffix" value=".jsp"/>
    </bean>
    <!--配置注解驱动支持:自动配置了HandlerMapping映射器和HandlerAdopter适配器-->
    <mvc:annotation-driven/>
    </beans>

关于springmvc.xml 中的一些配置解释如下。
①<mvc:annotation-driven/>:表示使用注解驱动 Spring MVC。
② <context:component-scan/>:定义要扫描注解的包。    
InternalResourceViewResolver:定义视图解析器,解析器中定义了前缀和后缀,这样视图就知道去 Web 工程的/WEB-INF view 文件夹中找到对应的 JSP 文件作为视图响应用户请求。
④<mvc:resources/>:为了避免拦截器将一些静态资源也给拦截了,通过属性 location和mapping就可以让拦截器对指定目录下的资源不进行拦截。

5、书写处理器,即我们的 Controller ,首先把类使用 @Controller 标识,标识该类交给 IOC 容器管理,其次在方 法上指定映射关系;
@Controller
public class TestController{
    @RequestMapping("/test")
    public String test(){
        //处理test请求
        System.out.println("TestController......test");
        //做出响应,直接返回视图的名字,视图解析会在指定目录中找到指定后缀的 该视图页面响应给前端页面
        return "zhuye";
    }
}

 测试结果

 

3.1 、RequestMapping注解

在Spring MVC 应用程序中,RequestDispatcher 这个 Servlet 负责将进入的 HTTP 请求路由到控制器的处理方法。
在对Spring MVC 进行配置的时候,需要指定请求与处理方法之间的映射关系。要配置Web请求的映射,就需要用到@RequestMapping 注解。

控制器的开发
控制器开发是Spring MVC的核心内容,主要分为以下三个步骤。

(1) 获取请求参数。

(2)处理业务逻辑。

(3)绑定模型和视图。 

3.2、请求参数的绑定

使用 ServletAPI 对象作为方法参数

SpringMVC 还支持使用原始 ServletAPI 对象作为控制器方法的参数。

    @RequestMapping("/login")
    //可以使用原生态的servlet API 进行处理
    public void login(HttpServletRequest request, HttpServletResponse response) throws IOException {
        System.out.println("UserController......login");
        String username = request.getParameter("username");
        System.out.println(username);
        response.sendRedirect("zhuye.jsp");
    }

普通参数的绑定

  • Spring MVC绑定请求参数是自动实现的,只要满足下面的规则即可。
  • 基本数据类型或 String 类型:要求参数名称必须和控制器中的方法的形参名称保持一致。(严格区分大小写)
  • POJO 类型:要求表单中的参数名称和POJO 类的属性名称保持一致,并且控制器方法的参数类型是POJO类型。
  • 集合类型:要求集合类型的请求参数必须在 POJO 中。在表单中的请求参数名称要和POJO中的集合属性名称相同。如果是给List集合中的元素赋值,则使用下标;如果给Map 集合中的元素赋值,则使用键值对。下面针对这几种情况进行示例演示。 

使用要求

  • 基本类型或者 String 类型:要求我们的参数名称必须和控制器中方法的形参名称保持一致。 (严格区分大小写)
  • POJO 类型,或者它的关联对象:要求表单中参数名称和 POJO 类的属性名称保持一致。并且控制器方法的参数类型是 POJO 类型。

集合类型,有两种方式:

第一种:

  • 要求集合类型的请求参数必须在 POJO 中。在表单中请求参数名称要和 POJO 中集合属性名称相同。
  • 给 List 集合中的元素赋值, 使用下标。
  • 给 Map 集合中的元素赋值, 使用键值对。

 第二种:

  • 接收的请求参数是 json 格式数据。需要借助一个注解实现。

基本类型参数:包括基本类型和 String 类型

请求地址提供请求参数:username、password。

    @RequestMapping("/login")
    public String login(String username,String password){
        System.out.println("UserController......login");
        System.out.println(username);
        System.out.println(password);
        return "zhuye";
    }

POJO 类型参数:实体类
在jsp页面中添加一个表单,并创建对应的实体类User(name与参数名称一致)

    @RequestMapping("/login")
    public void login(User user){
        //定义实体类,类的属性和请求参数的name属性一致,就会自动获取数据并封装到实体类中
        System.out.println("UserController......login");
        System.out.println(user);
    }

可以在控制器的参数中通过@ReqeustParam指定URL传递参数名称

@RequestParam 可以手动指定请求参数和参数的数据绑定 required 表示请求是必须传递该参数

关于@RequcstParam中的属性配置解释如下。    
required:值类型为布尔值,默认值为true,表示不允许参数为空,如果要允许为空,则设置为false。
defaultValue:当参数为空时候的默认值。

注意:注解@RequestParam可以对自定义简单类型的参数进行绑定,即如果使用@RequestParam,就无须设置controller方法的形参名称与request传入的参数名称一致。而不使用@RequestParam注解时,就要求controller方法的形参名称与request传入的参数名称一致,这样才能绑定成功。  

    @RequestMapping("/login")
    public String login(@RequestParam(value = "username",required = true)String name,String password){
        //@RequestParam 可以手动指定请求参数 和 参数的数据绑定 required 表示请求是必须传递该参数
        System.out.println("UserController......login");
        System.out.println(name);
        System.out.println(password);
        return "zhuye";
    }

如果要求绑定的参数一定不能为空,可以使用@RequestParam注解中的required属性来指定该形参是否必须传入,required属性为“true”指定参数必须传入。 

    @RequestMapping("/del")
    public String del(@RequestParam(required = true)Integer id){
        System.out.println("UserController......del");
        System.out.println(id);
        return "zhuye";
    }

ReuqestBody 主要是处理json串格式的请求参数,要求使用方指定header content-type:application/json
RequestBody 通常要求调用方使用post请求 

@RequestBody 只支持post请求,把数据变成key=value...结构的数据

@RequestMapping("/save")
    public String save(@RequestBody String data) {
        //@RequestBody 只支持post请求,把数据变成key=value...结构的数据
        System.out.println("UserController......save");
        System.out.println(data);
        return "zhuye";
    }

save.jsp 页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<form action="save" method="post">
    帐号:<input type="text" name="username" value=""><br>
    密码:<input type="password" name="password" value=""><br>
    年龄:<input type="text" name="age" value=""><br>
    <input type="submit" value="RequestBody测试"><br>
</form>
</body>
</html>

 请求参数中文乱码的解决

  • Filter 过滤器它是 JavaWeb 的三大组件之一。三大组件分别是:Servlet 程序、Listener 监听器、Filter 过滤器
  • Filter 过滤器它是 JavaEE 的规范。也就是接口
  • Filter 过滤器它的作用是:拦截请求,过滤响应。

到 web.xml 中去配置 Filter 的拦截路径

<!--字符集过滤器:把所有获取的内容进行中文转码-->
    <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>
    </filter>
    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

3.3、保存并获取属性参数

  • @RequestAttribute:获取HTTP 的请求(Request)对象属性值,用来传递给控制器的参数。
  • @SessionAttribute:在HTTP的会话(Session)对象属性值中,用来传递给控制器的
  • @SeasionAttributes:可以将数据模型中的数据存储到 Session 中。

4、转发和重定向

请求转发 :浏览器发送了一次请求,在服务器内部转发了一次;请求了一次,页面地址不会变化;

request.getRequestDispatcher("zhuye.jsp").forward(request,response);

重定向 :浏览器发送了一次请求,服务器让浏览器再去请求一次;请求了两次,页面地址会变化;

response.sendRedirect("zhuye.jsp");

springMVC的响应方式:请求转发

SpringMVC中可以使用两种方式进行重定向和转发: 

servlet的请求转发(forward)和重定向(sendRedirect)

使用ModelAndView对象进行转发和重定向

在Controller中,可以使用ModelAndView对象进行转发和重定向。使用ModelAndView对象进行转发时,可以将数据添加到ModelAndView对象中,然后将其返回给DispatcherServlet

DispatcherServlet会将其转发到指定的页面。使用ModelAndView对象进行重定向时,需要设置重定向的URL,然后将其返回给DispatcherServlet,DispatcherServlet会将其重定向到指定的URL。

@RequestMapping("/login1")
    public ModelAndView login1(User user){
        ModelAndView mv = new ModelAndView();
        System.out.println("UserController......login");
        System.out.println(user);
        //存储数据,默认存入request作用域
        mv.addObject("data","后端响应的数据");
        //指定响应的视图,执行的是请求转发
        mv.setViewName("zhuye");
        //请求转发和重定向使用关键词后不会再经过视图解析器,所以需要明确 位置/页面名.后缀
        //mv.setViewName("forward:/zhuye.jsp");
        //mv.setViewName("redirect:/zhuye.jsp");
        return mv;
    }
}

 GoodsController类

@Controller
public class GoodsController {
    @RequestMapping("/findAll")
    public ModelAndView findAll(){
        ModelAndView mv = new ModelAndView();
        //查询商品信息
        List<Goods> goodsList = new ArrayList<>();
        Goods g1 = new Goods();
        g1.setGid(1);
        g1.setGname("泡面");
        g1.setPrice(4.5);

        Goods g2 = new Goods();
        g2.setGid(2);
        g2.setGname("可乐");
        g2.setPrice(3.5);

        Goods g3 = new Goods();
        g3.setGid(3);
        g3.setGname("火腿肠");
        g3.setPrice(6.5);

        goodsList.add(g1);
        goodsList.add(g2);
        goodsList.add(g3);

        mv.addObject("goodsList",goodsList);
        mv.setViewName("zhuye");

        return mv;
    }
}
@Controller
public class UserController {
    @RequestMapping("/login")
    public ModelAndView login(User user){
        ModelAndView mv = new ModelAndView();
        System.out.println(user);
        if(user.getUsername().equals("admin") && user.getPassword().equals("666")){
            //我们重定向到商品查询
            mv.setViewName("redirect:/findAll");//重定向请求 /findAll 这个地址
        }else{
            mv.addObject("error","用户名或密码错误!");
            mv.setViewName("error");
        }
        return mv;
    }
}

 5、静态资源处理

页面插入图片 

 <img src="img/1.jpg"/>

在springmvc.xml配置文件中配置<mvc:resources>

mapping:指定静态资源的映射

location:指定静态资源的文件目录

<!--配置静态资源不拦截-->
    <mvc:resources mapping="/css/**" location="/css/"/>
    <mvc:resources mapping="/js/**" location="/js/"/>
    <mvc:resources mapping="/img/**" location="/img/"/>

6、拦截器

Spring MVC 的处理器拦截器类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理和后处理。用户还可以自定义一些拦截器来实现特定的功能。
在谈到拦截器,我们还要提到拦截器链(Interceptor Chain)这个词,它是将拦截器按照定的顺序联结成一条链。在访问被拦截的方法或者字段时,拦截器链中的拦截器就会按其定义的顺序被调用;

拦截器的定义

Spring MVC拦截器的实现一般有两利方式:第一种方式是要定义的Interceptor类要实现 Spring 的 HandlerInterceptor 接口;    第二种方式是继承实现了HandlerInterceptor接口的类,比如Spring已经提供的实现了HandlerInterceptor接口的抽象类HandlerInterceptorAdapter

<!--配置拦截器-->
    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <bean id="myInterceptor" class="com.zhan.interceptor.MyInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>

接口中定义了三个方法,其含义解释如下。

  • preHandle:在处理器之前执行的前置方法,如果该方法返回 true,则请求继续向下进行,否则请求不会继续向下进行,处理器也不会被调用。    
  • postHandle:在处理器之后执行的后置方法。
  • afterCompletion:只要该拦截器中的pr eHandle 方法返回 true,该方法就会在渲染视图后被调用。

注:拦截器中的前置方法返回值决定了后续的流程是否执行,同时需要注意的是后置方法postHandle是在handler方法(Controller)成功执行之后、dispatcher渲染视图之前执行。因此如果handler 方法抛出异常,则 postHandle也是不会执行的。但 afterCompletion 只要前置方法返回true,后面无论是否抛出异常,都会在视图渲染结束后执行。 

从输出结果可以看出,当其中一个前置方法返回false,那么后面的前置方法、控制器方法、后置方法都不会执行,只有对应返回true的拦截器的完成方法(afterCompletion)才会逆序执行。

public class MyInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("MyInterceptor......preHandle");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("MyInterceptor......postHandle");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("MyInterceptor......afterCompletion");
    }
}

未登录拦截的原理

判断用户是否登录(首先登录时需要把用户信息存入session,后续只要判断session中是否存在用户信息),如果没有登录则拦截。

public class MyInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("MyInterceptor......preHandle(前置通知)");
        //登录请求不拦截,其它请求查看session域
        String servletPath = request.getServletPath();
        if(servletPath.equals("/login")){
            return true;
        }else{
            //获得session域中的user对象
            User user = (User) request.getSession().getAttribute("user");
            if(user!=null){
                return true;
            }else{
                return false;
            }
        }
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("MyInterceptor......postHandle(后置通知)");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("MyInterceptor......afterCompletion(最终通知)");
    }
}

拦截 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值