java web 45 : SpringMVC

1、模式一(Model One):JSP(只使用JSP进行开发)
    Servlet:本质是一段Java程序,适合处理业务逻辑,但是Servlet不适合输出一个html网页(因为在Servlet中输出网页,得通过response获取流,通过out.write一行一行将html标签等内容输出到浏览器中)
    
    Html:是用于开发网页的语言,适合作为网页输出,但是html是一个静态Web资源,无法展示动态的数据
    
    JSP:也是开发网页的语言,也可以输出一个网页(html),并且JSP中可以书写Java代码(或者JSP标签,其实底层也是Java代码)展示动态数据。
    JSP的出现既解决了Servlet不适合输出网页的问题,同时也解决了HTML无法展示动态数据的问题!
    在一些中小型项目中只用JSP进行开发(持续了一段时间),JSP负责的工作:
    (1)获取请求中携带的数据,对请求进行处理
    (2)如果在处理的过程中需要访问数据库,JSP中可以书写Java代码访问数据库
    (3)请求处理的结果仍然是由JSP负责响应
    JSP中要处理很多的内容,必然要写很多Java代码,这样会导致JSP内部的HTML代码和Java代码混杂在一起,造成JSP页面结构的混乱,可读性变差,后期难以维护,代码难以复用!

2、模式二(Model Two):Servlet+JavaBean+JSP:
    (1)Servlet:接收请求中的数据(请求参数)、调用某一个JavaBean对请求进行处理、调用某一个JSP展示请求处理的结果
        将请求数据封装到JavaBean内部
        调用JavaBean方法处理请求
        
    (2)JavaBean:处理请求(封装数据、处理业务逻辑、访问数据库)
        业务Bean: 负责处理业务逻辑
        实体Bean: 负责封装数据
        User类(username/password/nickname/email..)
        
    (3)JSP:只负责展示/响应对请求处理的结果

-----------------------------------------
** MVC设计模式:
-----------------------------------------
MVC设计模式是一种通用的软件编程思想,不仅仅适用于Java语言。
在MVC设计模式中认为, 任何软件都可以分为三部分组成:
(1)控制程序流转的控制器(Controller)
(2)封装数据处理数据的模型(Model)
(3)负责展示数据的视图(view)
并且在MVC设计思想中要求一个符合MVC设计思想的软件应该保证上面这三部分相互独立,互不干扰,每一个部分只负责自己擅长的部分。
如果某一个模块发生变化,应该尽量做到不影响其他两个模块。这样做的好处是,软件的结构会变得更加的清晰,可读性强。有利于后期的扩展和维护,并且代码可以实现复用。

******************************************************************************************************

 

(1).用户发送请求 至 前端控制器(DispatcherServlet);

提示:DispatcherServlet的作用:接收请求,调用其它组件处理请求,响应结果,相当于转发器、中央处理器,是整个流程控制的中心

(2).前端控制器(DispatcherServlet)收到请求后调用处理器映射器(HandlerMapping)

处理器映射器(HandlerMapping)找到具体的Controller(可以根据xml配置、注解进行查找),并将Controller返回给DispatcherServlet;

(3).前端控制器(DispatcherServlet)调用处理器适配器(HandlerAdapter)。处理器适配器经过适配调用具体的Controller;(Controller--> service --> Dao --> 数据库)

Controller执行完成后返回ModelAndView,

提示:Model(模型数据,即Controller处理的结果,Map) View(逻辑视图名,即负责展示结果的JSP页面的名字)

处理器适配器(HandlerAdapter)将controller执行的结果(ModelAndView)返回给前端控制器(DispatcherServlet);

(4).前端控制器(DispatcherServlet)将执行的结果(ModelAndView)传给视图解析器(ViewReslover)

视图解析器(ViewReslover)根据View(逻辑视图名)解析后返回具体JSP页面

(5).前端控制器(DispatcherServlet)根据Model对View进行渲染(即将模型数据填充至视图中);

前端控制器(DispatcherServlet)将填充了数据的网页响应给用户。

其中整个过程中需要开发人员编写的部分有ControllerServiceDaoView;

*************************************************************************************************
在web.xml中配置前端控制器

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    version="2.5">
    <display-name>test_springMVC</display-name>
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.htm</welcome-file>
        <welcome-file>index.jsp</welcome-file>
        <welcome-file>default.html</welcome-file>
        <welcome-file>default.htm</welcome-file>
        <welcome-file>default.jsp</welcome-file>
    </welcome-file-list>

    <!-- 配置springmvc的前端控制器(DispatcherServlet),将请求交给springMVC处理-->
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>  <!-- 为servlet配置初始参数 -->
            <param-name>contextConfigLocation</param-name><!-- 固定写法 -->
            <param-value>classpath:springmvc-config.xml</param-value><!-- 配置springmvc核心文件的位置 -->
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
        <!-- /* : 拦截静态资源(html/css/js/图片/视频..), / : 拦截静态资源,但是不包括jsp -->
    </servlet-mapping>
    
    <!-- 配置过滤器,解决POST提交的中文参数乱码问题 -->
    <filter>
        <filter-name>encodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern> <!-- 表示对所有请求进行过滤 -->
    </filter-mapping>

</web-app>

配置springMVC核心配置文件

<?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:mvc="http://www.springframework.org/schema/mvc"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/mvc
                        http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
                        http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
                        http://www.springframework.org/schema/context
                          http://www.springframework.org/schema/context/spring-context-4.0.xsd">
    
    <!-- 1.配置前端控制器放行静态资源(html/css/js等,否则静态资源将无法访问) -->
    <mvc:default-servlet-handler/>
    
    <!-- 2.配置注解驱动,用于识别注解(比如@Controller) -->
    <mvc:annotation-driven></mvc:annotation-driven>
    
    <!-- 3.配置需要扫描的包:spring自动去扫描 base-package 下的类,
        如果扫描到的类上有 @Controller、@Service、@Component等注解,
        将会自动将类注册为bean 
     -->
    <context:component-scan base-package="com.tedu.controller">
    </context:component-scan>
    
    <!-- 4.配置内部资源视图解析器
        prefix:配置路径前缀
        suffix:配置文件后缀
        /WEB-INF/pages/home.jsp
     -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
    
    
</beans>

实现controller

package com.tedu.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

/*
 * 让spring框架创建spring实例,如果当前类所在的包配置了spring容器包扫描,具有
 * 该注解的类,就会作为bean注册到spring容器中,由spring容器创建实例
 */
@Controller
/*
 * @RequestMapping("/hc") 加这行注解后,访问路径要加一层/hc
 * 要求controller内方法的访问路径不能冲突
 */
public class HelloController {
    
    //为当前方法配置访问路径访问括号里的路径,就会执行这个方法
    @RequestMapping("/hello")
    public String testHello() {
        System.out.println("hello springmvc...");
        
        //  跳转到/WEB-INF/pages/home.jsp
        return "home";
    }
}

 

pojo类

package com.tedu.pojo;
/*
 * 用于封装用户信息
 */
public class User {
    private String name;
    private Integer age;
    private String addr;
    
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
        System.out.println("setName..."+name);
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
        System.out.println("setAge..."+age);
    }
    public String getAddr() {
        return addr;
    }
    public void setAddr(String addr) {
        this.addr = addr;
        System.out.println("setAddr..."+addr);
    }
    @Override
    public String toString() {
        return "User [name=" + name + ", age=" + age + ", addr=" + addr + "]";
    }
    
}

springMVC的参数绑定、跳转处理、响应数据

package com.tedu.controller;

import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.ServletRequestDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.RequestMapping;

import com.tedu.pojo.User;

@Controller
public class ParamController {
    /**
     * springmvc的参数绑定 
     */
    
    /**
     * 1.简单类型的参数绑定
     * http://localhost:8080/test_springMVC/testParam01?name=张飞&age=35&addr=河北
     * 在方法上声明和请求参数同名的形参
     */
    @RequestMapping("/testParam01")
    public String testParam01(String name, Integer age, String addr) {
        System.out.println("ParamController.testParam01()");
        System.out.println("name="+name+" age="+age+" addr="+addr);
        return "home";
    }

    @RequestMapping("/testParam02")
    public String testParam02(String user, String psw, String[] like) {
        System.out.println("ParamController.testParam01()");
        System.out.println("user="+user+" psw="+psw+" like="+Arrays.toString(like));
        return "home";
    }
    /**
     * 2.包装类型的参数绑定(将请求中的参数直接封装到对象中)
     * http://localhost:8080/test_springMVC/testParam03?name=赵云&age=28&addr=北京昌平
     * 可以直接将请求中的参数封装到pojo对象中,寻找对应的setName setAge setAddr方法
     */
    @RequestMapping("/testParam03")
    public String testParam03(User user) {
        System.out.println(user);
        return "home";
    }
    /**
     * 3.日期类型的参数绑定(可能出现400错误,表示参数类型不匹配)
     * http://localhost:8080/test_springMVC/testParam04?date=2020/08/24 9:39:50
     * 传递日期参数时,springmvc默认用/分隔
     * 在springmvc中,提供了@InitBinder注解,用于指定自定义的日期转换格式,
     * 在接受日期类型的参数时,会自动按照自定义的日期格式进行转换。
     */
    @RequestMapping("/testParam04")
    public String testParam04(Date date) {
        System.out.println(date);
        return "home";
    }
    
    // 自定义日期格式转换器,将springmvc默认以斜杠(/)分隔日期改为以横杠分隔(-)
    @InitBinder
    public void InitBinder (ServletRequestDataBinder binder){
        binder.registerCustomEditor(java.util.Date.class, 
            new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"), true)
        );
    }
    
    /**
     * 4.乱码处理
     * 接收请求中的user和like两个参数的值
     * 使用get提交表单中的user和like,没有乱码
     * 使用post提交出现乱码
     * springMVC针对post提交中文参数有乱码提供了解决方案
     * 只需要启用springMVC提供的乱码处理过滤器即可解决
     */
    @RequestMapping("/testParam05")
    public String testParam05(String user,String[] like) {
        System.out.println("user="+user);
        System.out.println("like="+Arrays.toString(like));
        return "home";
    }
    
    /**
     * 5.实现请求转发
     * 转发是一次请求一次响应
     * 转发前后地址栏不会发生变化
     * 转发只能是同一个应用内部的资源跳转
     * 转发可以和域对象配合使用,带数据到目的地
     */
    //1)从Controller中的方法直接转发到test.jsp
    @RequestMapping("/testForward")
    public String testForward(Model model) {
        System.out.println("testForward()...");
        model.addAttribute("name","刘德华");//往request域中存数据(model底层就是request域)
        return "test";//返回值是jsp的名字,默认就表示转发到jsp
    }
    //2)从Controller中的方法转发到另外一个方法
    @RequestMapping("/test02")
    public String test02(Model model) {
        System.out.println("test02()...");
        model.addAttribute("age","30");
        return "forward:testForward"; // forward: 是转发到方法的固定前缀
        //从test02转发到testForward,再转发到test.jsp
    }
    
    /**
     * 6.实现重定向
     * 重定向是两次请求,两次响应
     * 重定向前后地址栏会发生变化
     * 重定向没有限制,可以是同一个web应用或不用web应用之间的资源
     * 重定向不能配合request域携带数据
     */
    //1)从Controller方法重定向到其他的Controller方法
    @RequestMapping("/testRedirect")
    public String testRedirect() {
        System.out.println("testRedirect()...");
        return "redirect:/testRedirect01"; // redirect: 重定向的固定前缀
        // 重定向到 /testRedirect02 对应的方法
    }
    @RequestMapping("/testRedirect01")
    public String testRedirect01() {
        System.out.println("testRedirect01()...");
        return "test"; //转发到test.jsp
    }
    //2)从当前应用重定向到其他web应用
    @RequestMapping("/testRedirect02")
    public String testRedirect02() {
        System.out.println("testRedirect02()...");
        return "redirect:http://localhost:8080/test02/html01.html";    
    }
    //3)重定向到其他服务器
    @RequestMapping("/testRedirect03")
    public String testRedirect03() {
        System.out.println("testRedirect03()...");
        return "redirect:http://www.baidu.com";    
    }
    
    /**
     * 7.通过model响应数据(Model+转发带数据到jsp)
     */
    @RequestMapping("/testModel")
    public String testModel(Model model) {
        //可以将数据存入Model中(底层是request域)
        User u1 = new User();
        u1.setName("韩信");
        u1.setAge(28);
        u1.setAddr("南京");
        model.addAttribute("user", u1);
        return "test";
    }
}

 

posted @ 2020-08-23 11:10  Saturn5  阅读(27)  评论(0)    收藏  举报