SpringMVC基础入门篇

文章目录

SpringMVC

第一章 SpringMVC概述

1.1 SpringMVC简介

​ springMVC是基于spring的一个框架,实际上就是spring的一个模块,专门做web开发的。理解是servlet的一个升级。

​ web开发底层是servlet,框架是在servlet基础上面加入一些功能,让你的web开发更方便。

web开发底层是servlet,springmvc中一个对象是servlet:DispatherServlet
DispatherServlet:负责接收用户的所有请求,用户吧请求给了DispatherServlet,之后DispatherServlet吧请求转发给我们的Controller对象,最后是Controller对象处理请求。

1.2 SpringMVC 优点

1、基于MVC架构

​ 基于 MVC 架构,功能分工明确。解耦合。

2、容易理解,上手快;使用简单

​ 就可以开发一个注解的 SpringMVC 项目,SpringMVC 也是轻量级的,jar 很小。不依赖的 特定的接口和类。

3、 作 为 Spring 框 架 一 部 分 , 能 够 使 用 Spring 的 IoC 和 Aop 。

​ 方 便 整 合 Strtus,MyBatis,Hiberate,JPA 等其他框架。

4、SpringMVC 强化注解的使用,在控制器,Service,Dao 都可以使用注解。方便灵活。

​ 使用@Controller 创建处理器对象,@Service 创建业务对象,@Autowired 或者@Resource 在控制器类中注入 Service, Service 类中注入 Dao。

1.3 入门案例

	需求:用户在页面发起一个请求,请求交给springmvc的控制器对象,
  			并显示请求的处理结果(在结果页面显示一个欢迎语句)。
1.3.1 实现步骤
    1、新建web Maven工程
    
    2、加入依赖
        spring-webmvc 依赖,间接吧spring的依赖都加入到项目中
        jsp,servlet依赖
        
    3、重点:在web.xml中注册springmvc框架的核心对象DispatcherServlet。
        1)DispatcherServlet叫做中央调度器,是一个servlet,它的父类是继承HttpServlet
        2)DispatcherServlet也叫做前端控制器,(front controller)
        3)DispatcherServlet负责接收用户提交的请求,调用其他的控制器对象,并把请求的处理结果显示给用户。
        
    4、创建一个发起请求的页面 index.jsp
    
    5、创建控制器类
        1)在类的上面加入@Controller注解,创建对象,并放入到spring容器中。
        2)在类中的方法上面加入@Requestmapping注解。
    6、创建一个作为结果的jsp,显示请求的处理结果。
    
    7、创建springmvc的配置文件(spring的配置文件一样)
        1)声明组件扫描器,指定@Controller注解所在的包名。
        2)声明视图解析器,帮助处理视图的。
1.3.2 SpringMVC请求的处理流程

​ 1)发起some.do

​ 2)tomcat(web.xml——>url-pattern 知道*.do的请求给DispatcherServlet)

​ 3)DispatcherServlet(根据springmvc.xml配置知道 some.do——>doSome())

​ 4)DispatcherServlet吧some.do转发给MyController.doSome()方法

​ 5)框架执行doSome()把得到ModerlAndView进行处理,转发到show.jsp。

1.3.3 Springmvc 执行过程源代码分析

​ 1、tomcat启动,创建容器的过程

通过load-on-start标签指定的1,创建DispatcherServlet对象。
DispatcherServlet它的父类是继承HttpServlet的,它是一个servlet,在被创建时,会执行init()方法。
在init()方法中
//创建容器,读取配置文件
WebApplicationContext context = new ClassPathXmlApplicationContext("springmvc.xml");

//把容器对象放入ServletContext中
getServletContext().setAttribute(key, context)

上面创建容器作用:创建@Controller注解所在的类的对象,创建MyController对象。
这个对象放入到springmvc的容器中,容器是map,类似map.put("myController",MyController对象)

​ 2、请求的处理流程

1)执行servlet的service()方法
protected void service(HttpServletRequest request, HttpServletResponse response)

protected void doService(HttpServletRequest request, HttpServletResponse response)

DispatcherServlet.doDispatch(request, response){
	调用MyController的do.some()方法
}

​ 3、流程图

在这里插入图片描述

第二章 SpringMVC 注解式开发

2.1 @RequestMapping 定义请求规则

2.1.1 指定模块名称
一个@Controller 所注解的类中,可以定义多个处理器方法。当然,不同的处理器方法
所匹配的 URI 是不同的。这些不同的 URI 被指定在注解于方法之上的@RequestMapping 的
value 属性中。但若这些请求具有相同的 URI 部分,则这些相同的 URI,可以被抽取到注解在
类之上的@RequestMapping 的 value 属性中。此时的这个 URI 表示模块的名称。URI 的请求
是相对于 Web 的根目录。

​ 示例:

@RequestMapping(value = "/test")
public class MyController {}
//value:所有请求地址的公共部分,叫做模块名称
//位置:放在类的上面
2.1.2 对请求提交方式的定义
对于@RequestMapping,其有一个属性 method,用于对被注解方法所处理请求的提交
方式进行限制,即只有满足该 method 属性指定的提交方式的请求,才会执行该被注解方法。
Method 属性的取值为 RequestMethod 枚举常量。常用的为 RequestMethod.GET 与
RequestMethod.POST,分别表示提交方式的匹配规则为 GET 与 POST 提交。
    如果不指定用哪一种请求方式,则表示都可以接收。

示例

//Post请求方式
@RequestMapping(value = {"/other.do"}, method = RequestMethod.POST)
public ModelAndView doOther() {}
    
//get请求方式    
@RequestMapping(value = "/some.do", method = RequestMethod.GET)
public ModelAndView doSome() {

2.2 处理器方法的参数

​ 处理器方法可以包含以下四类参数,这些参数会在系统调用时由系统自动赋值,即程序 员可在方法内直接使用。

➢ HttpServletRequest 
➢ HttpServletResponse 
➢ HttpSession
➢ 请求中所携带的请求参数
2.2.1 逐个接收

只要保证请求参数名与该请求处理方法的参数名相同即可。

逐个接收请求参数:
     * 要求:处理器方法的形参名和请求中参数名必须一致
     * 同名的请求参数赋值给同名的形参,Controller中方法形参的位置无关。
     
框架接收请求参数
	1、使用request对象接收请求参数
		String strName = request.getParameter("name");
		String strAge = request.getParameter("age");
	2、springmvc框架通过DispatcherServlet 调用MyControllerdoSome()方法
		调用方法时,按名称对应,把接收的参数赋值给形参
		doSome(StrName, Integer.parseInt(strAge));
		框架会提供类型转换得到功能,能把String转为intlong,double,float等类型。
		
400状态码是客户端错误,表示提交的请求参数过程中,发生了问题。

Controller方法代码

    @RequestMapping(value = {"/receiveProperty.do"}, method = RequestMethod.GET)
    public ModelAndView doOther(String name, Integer age) {
        System.out.println("name = " + name+", age = "+age);
        ModelAndView mv = new ModelAndView();
        mv.addObject("name", name);
        mv.addObject("age", age);
        mv.setViewName("other");
        return mv;
    }

other.jsp

<body>
<h3>/WEB-INF/view/show.jsp 从request作用域中获取数据</h3>
<h3>myName数据:${name}</h3>
<h3>myAge数据:${age}</h3>
</body>
2.2.2 请求参数中文乱码问题

在提交请求参数时,get请求方式中文没有乱码。

使用POST方式提交请求时,中文有乱码,需要使用过滤器处理乱码问题。(可以自定义,也可以用框架)。

web.xml中注册声明过滤器

    <!--    注册声明过滤器,解决POST请求乱码问题-->
    <filter>
        <filter-name>characterEncodingFilter</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>
        <!--        强制请求对象(HttpServletRequest)使用encoding编码的值-->
        <init-param>
            <param-name>forceRequestEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
        <!--        强制应答对象(HttpServletResponse)使用encoding编码的值-->
        <init-param>
            <param-name>forceResponseEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>characterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
2.2.3 源码分析
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        //表示值"utf-8"
        String encoding = this.getEncoding();
        if (encoding != null) {
            //isForceRequestEncoding() = true
            if (this.isForceRequestEncoding() || request.getCharacterEncoding() == null) {
                request.setCharacterEncoding(encoding);
            }
			// isForceResponseEncoding() = true
            if (this.isForceResponseEncoding()) {
                response.setCharacterEncoding(encoding);
            }
        }

        filterChain.doFilter(request, response);
    }
2.2.4 请求中参数名形参名不一致

@RequestParam:解决请求中参数名和形参名不一致的问题。

属性:

​ 1)value,请求中的参数名称。

​ 2)required 是一个Boolean类型,默认时true,

​ true:表示请求中必须包含此参数。

位置:在处理器方法的形参定义的前面。

@RequestMapping(value = {"/receiveParam.do"}, method = RequestMethod.POST)
    public ModelAndView receiveParam(@RequestParam("Pname",required = false) String name, @RequestParam("Page") Integer age) {}
2.2.5 对象参数接收

​ 将处理器方法的参数定义为一个对象,只要保证请求参数名与这个对象的属性同名即可。 项目:receiveParameters-object。在 receiveParameters-property 基础上修改。

1、处理器方法形参是Java对象,这个对象的属性名和请求中的参数名一样的

2、框架会创建形参的Java对象,给属性赋值。请求中的参数是name,框架会调用setName()

定义student类

/**
 * 保存请求参数值的一个普通类
 */
public class Student {
    //    属性名和请求中参数名一样
    private String name;
    private Integer age;
    
	此处省略了set,get,以及无参数构造方法
...
}

前端页面 param.jsp

<p>使用Java对象接收请求参数</p>
<form action="test/receiveObject.do" method="post">
    姓名:<input type="text" name="name"><br/>
    年龄:<input type="text" name="age"><br/>
    <input type="submit" value="提交参数">
</form>

Controller中的方法


    /**
     * 处理器方法形参是Java对象,这个对象的属性名和请求中的参数名一样的
     * 框架会创建形参的Java对象,给属性赋值。请求中的参数是name,框架会调用setName()
     *
     * @return
     */
    @RequestMapping(value = {"/receiveObject.do"}, method = RequestMethod.POST)
    public ModelAndView receiveObject(Student stu, School school) {
        System.out.println("stu = " + stu);
        System.out.println("school = " + school);
        ModelAndView mv = new ModelAndView();
        mv.addObject("student", stu);
        mv.setViewName("param");
        return mv;
    }

注意:

//1、如果传入多个形参都是对象类型,且两个对象之间有相同的属性名称,那么框架会对其两个对象的相同属性都进行赋值。
public ModelAndView receiveObject(Student stu, School school) {}
//Student类和School类中有相同的属性name,则框架会将其都赋值。

2.3 处理器方法的返回值

使用@Controller 注解的处理器的处理器方法,
其返回值常用的有四种类型:
➢ 第一种:ModelAndView 
➢ 第二种:String 
➢ 第三种:无返回值 void 
➢ 第四种:返回自定义类型对象 根据不同的情况,使用不同的返回值。
2.3.1 返回ModelAndView
	若处理器方法处理完后,需要跳转到其它资源,且又要在跳转的资源间传递数据,此时 处理器方法返回 ModelAndView 比较好。
	当然,若要返回 ModelAndView,则处理器方法中 需要定义 ModelAndView 对象。 
	在使用时,若该处理器方法只是进行跳转而不传递数据,或只是传递数据而并不向任何 资源跳转(如对页面的 Ajax 异步响应),此时若返回 ModelAndView,则将总是有一部分多余:要么 Model 多余,要么 View 多余。
	即此时返回 ModelAndView 将不合适。
2.3.2 返回String

​ 处理器方法返回的字符串可以指定逻辑视图名,通过视图解析器解析可以将其转换为物理视图地址。

如果是要返回普通的字符串,而不是返回视图,我们只需要添加一个注解@ResponseBody

//处理器方法返回String -- 表示逻辑视图名称,需要配置视图解析器
	@RequestMapping(value = {"/returnString-view.do"}, method = RequestMethod.POST)
// @ResponseBody 加上这个注解后,表明返回的是普通的字符串,而不是视图。
    public String receiveParam(String name, Integer age, HttpServletRequest request) {
        System.out.println("name = " + name + " ,age = " + age);
        request.setAttribute("name", name);
        request.setAttribute("age", age);
//        show:逻辑视图名称,项目中配置了视图解析器
//        框架对视图执行forward转发操作。
        return "show";
    }
2.3.3 返回void

​ 若处理器对请求处理后,无需跳转到其它任何资源,此时可以让处理器方法返回 void。

​ 不能表示数据,也不能表示视图,在处理ajax的时候,可以使用void返回值。通过HttpServletResponse输出数据相应ajax请求。

​ ajax请求服务器端返回额的就是数据,和视图无关。

​ 使用json依赖(pom.xml)

    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-core</artifactId>
      <version>2.13.1</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.13.1</version>
    </dependency>

前端页面(index.jsp)

<script type="text/javascript">
    $(() => {
        $("#btn").click(function () {
            $.ajax({
                url: "test/returnVoid-ajax.do",
                data: {
                    name: $("#userName").val(),
                    age: $("#userAge").val()
                },
                type: "post",
                dataType: "json",
                success: function (resp) {
                    alert(resp.name+"\n"+resp.age)
                    console.log("name = "+resp.name)
                    console.log("age = "+resp.age)
                }
            })
        });
    });
</script>

MyController类中的方法响应前端的ajax

    @RequestMapping(value = {"/returnVoid-ajax.do"}, method = RequestMethod.POST)
    public void returnVoid(String name, Integer age, HttpServletResponse response) throws IOException {
        System.out.println("name = " + name + " ,age = " + age);
//        处理ajax,使用jsonstu格式
//        模拟调用service完成,返回Student对象
        Student stu = new Student(name, age);
//        把结果的对象转为json格式的数据
        String json = "";
        if (stu != null) {
            ObjectMapper om = new ObjectMapper();
            json = om.writeValueAsString(stu);
            System.out.println("student转化为json对象:" + json);
        }
//        输出数据,响应ajax的请求
        response.setContentType("application/json;charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.println(json);
        writer.flush();
        writer.close();
    }
2.3.4 返回Object
	1、处理器方法也可以返回 Object 对象。这个 Object 可以是 Integer,String,自定义对象, Map,List 等。
	2、但返回的对象不是作为逻辑视图出现的,而是作为直接在页面显示的数据出现的,与视图无关。
    3、返回对象,需要使用@ResponseBody 注解,将转换后的 JSON 数据放入到响应体中。
    4、可以使用对象表示的数据,响应ajax请求。

​ 现在做ajax,主要使用json的数据格式。实现步骤:

1、加入处理json的工具库的依赖,springmvc默认使用的是jackson。
2、在springmvc配置文件之间加入<mvc:annotation-driven> 注解驱动。
等价于<==>            json = om.writeValueAsString(stu);

3、在处理器方法的上面加入ResponseBody注解
等价于<==>response.setContentType("application/json;charset=utf-8");
         PrintWriter writer = response.getWriter();
         writer.println(json);

springmvc 处理器方法返回Object,可以转为json输出到浏览器,响应ajax的内部原理:

1、<mvc:annotation-driven>注解驱动。
	注册驱动实现的功能是 完成Java对象到json,xml,text,二进制等数据格式的转换。
	HttpMessageConveter接口:消息转换器。
		功能:定义了Java对象转为json,xml等数据格式的方法。这个接口有很多的实现类。
			这些实现类完成了java对象到json,java对象到xml,Java对象到二进制数据的转换。
		七个实现类:
				1)MappingJackson2HttpMessageConverter(使用jackson工具库中的ObjectMapper实现Java对象转为json字符串)

下面两个方法是控制器类把结果输出给浏览器时使用的

//指定转换器是否可将 clazz 类型的对
//象写到响应流中,响应流支持的媒体类型在 MediaType 中定义。
boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType);

//将 T 类型的对象写
//到响应流中,同时指定相应的媒体类型为 contentType
void write(T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException;

返回自定义对象形式

1、添加jackson依赖

2、在springmvc.xml中注册驱动
	<mvc:annotation-driven/>

3MyController类中的方法 
	@RequestMapping(value = {"/returnStudentJson-ajax.do"}, method = RequestMethod.POST)
    @ResponseBody
    public Student returnStudentJson(String name, Integer age, HttpServletResponse response) throws IOException {
        System.out.println("这是注解驱动的方式,name = " + name + " ,age = " + age);
//        处理ajax,使用jsonstu格式
//        模拟调用service完成,返回Student对象
        Student stu = new Student(name, age);
        return stu;
    }
@ResponseBody:
		1)作用:把处理器方法返回对象转化为json后,通过HttpServletResponse输出给浏览器。
        2)位置:方法的定义上面。和其他注解没有顺序的关系。

4、返回对象框架的的处理流程:
        1)框架会把返回Student类型,调用框架中的ArrayList<HttpMessageConvertor>中每个类的canWrite()方法,
            检查哪个HttpMessageConveter接口的实现类能处理Student类型的数据---							                       MappingJackson2HttpMessageConveter类。
            
        2)框架会调用实现类的write()MappingJackson2HttpMessageConveterwrite()方法,把李四同学的student对象转			为json,调用JacksonObjectMapper实现转为json。
            
        3)框架会调用@ResponseBody2的结果数据输出到浏览器,ajax请求处理完成。

返回List集合

    @RequestMapping(value = {"/returnStudentListJson-ajax.do"}, method = RequestMethod.POST)
    @ResponseBody
    public List<Student> returnStudentListJson(String name, Integer age, HttpServletResponse response) throws IOException {
        List<Student> studentList = new ArrayList<Student>();
        System.out.println("这是注解驱动的方式,name = " + name + " ,age = " + age);
        Student stu = new Student(name, age);
        studentList.add(stu);
        studentList.add(new Student("邓进",30));
        studentList.add(new Student("张三",40));
//        转为json数组
        return studentList;
    }

注意

处理器方法返回的是String,String表示数据的,不是视图。
区分返回值String是数据,还是视图,看有没有@ResponseBody注解,如果有@ResponseBody注解,返回String就是数据,反之就是视图。

示例:

    /**
     * 返回字符串
     * 默认使用 "Content-Type: text/plain;charset=ISO-8859-1" 导致中文有乱码
     * 解决方案:给RequestMapping 增加一个属性produces,使用这个属性指定新的Context-Type.
     *
     * @return
     */
    @RequestMapping(value = {"/returnString.do"}, method = RequestMethod.POST, produces = "text/plain;charset=utf-8")
    @ResponseBody
    public String returnString() {
        return "fashion show!你好!";
    }

2.4 解读<url-pattern/>

只有当使用<url-pattern>/<url-pattern/>的时候,才需要静态资源的配置。

2.4.1 第一种处理静态资源的方式

​ <mvc:default-servlet-handler/>

使用斜杠" / "
	当你的项目使用了 / ,它会替代 tomcat中的default。
	导致所有的静态资源都给DispatcherServlet处理,默认情况下DispatcherServlet没有处理静态资源的能力。
	没有控制器对象能处理静态资源的访问。所以静态资源(html,js,图片,css)都是404错误。
动态资源some.do是可以访问的,因为我们程序中有MyController控制器对象,能处理some.do的请求。
需要在springmvc配置文件加入<mvc:default-servlet-handler/>,
原理是:加入这个标签后,框架会创建控制器对象DefaultServletHttpRequestHandler(类似我们自己创建的MyController)。
		DefaultServletHttpRequestHandler这个对象可以把接收的请求转发给 tomcat的default这个servlet。

注意

​ <mvc:annotation-driven/>
​ default-servlet-handler标签 和@RequestMapping注解有冲突,需要加入annotation-driven 解决问题。

2.4.2 第二种处理静态资源的方式

​ <mvc:resources/>

    <!--    第二种处理静态资源的方式
            mvc:resources :加入后框架会创建 ResourceHttpRequestHandler这个处理器对象。
            让这个对象来处理静态资源的访问,不依赖tomcat服务器。
            mapping:访问静态资源的uri地址,使用通配符**
            location:静态资源在你的项目中的目录位置。
            /images/**:表示images下的所有目录和所有文件。
            /images/:表示静态资源的目录位置。
    -->

    <mvc:resources mapping="/images/**" location="/images/"/>
    <mvc:resources mapping="/html/**" location="/html/"/>

Tips

我们可以把所有的静态资源都放到一个static文件目录下,这样我们的就只需要配置一个resource标签。
<mvc:resources mapping="/static/**" location="/static/"/>

2.5 解决路径问题

2.5.1 参考地址
参考地址:
	在你的页面中,访问地址不加 " / "
	访问的是:http://localhost:8080/spring_url_pattern/index.jsp
		路径是:http://localhost:8080/spring_url_pattern/
		资源index.jsp
	在index.jsp发起user/some.do请求,访问地址变为http://localhost:8080/spring_url_pattern/user/some.do
		当你的地址,没有以斜杠开头,例如 user/some.do,当你点击链接时,访问的地址是当前页面的地址加上链接的地址。
		http://localhost:8080/spring_url_pattern/ + user/some.do

缺点:
	参考地址可能会发生变化,导致出现404错误。
解决方案:
	1)加入${pageContext.request.contextPath}
	2)使用base标签。在你的页面中,所有不带斜杠的地址都是参考base标签,将其作为参考地址,
			使用base标签的地址 + user/some.do 组成访问地址。
<base href="http://localhost:8080/spring_url_pattern/"/>

动态获取参考地址:
String basePath = request.getScheme() + "://" + 
request.getServerName() + ":" + request.getServerPort() + 
request.getContextPath() + "/";
在页面中,访问地址加上 " / "
访问的是:http://localhost:8080/spring_url_pattern/index.jsp
路径是:http://localhost:8080/spring_url_pattern/
资源是:index.jsp

点击/user/some.do  访问地址变为http://localhost:8080/user/some.do
参考地址:服务器地址,也就是http://localhost:8080/

如果你的资源不能访问
加上${pageContext.request.contextPath}
<a href = "${pageContext.request.contextPath}/user/some.do">发起user/some.do的请求</a>
等价于<===>
<a href = "/spring_url_pattern/user/some.do">发起user/some.do的请求</a>

第三章 SSM整合开发

​ SSM: SpringMVC + Spring + MyBatis.

​ SpringMVC:视图层,界面层,负责接收请求,显示处理结果的。
​ Spring:业务层,管理service,dao,工具类对象的。
​ MyBatis:持久层, 访问数据库的。

用户发起请求--SpringMVC接收--Spring中的Service对象--MyBatis处理数据

SSM整合也叫做SSI (IBatis也就是mybatis的前身), 整合中有容器。
1.第一个容器SpringMVC容器, 管理Controller控制器对象的。
2.第二个容器Spring容器,管理Service,Dao,工具类对象的
我们要做的把使用的对象交给合适的容器创建,管理。 把Controller还有web开发的相关对象
交给springmvc容器, 这些web用的对象写在springmvc配置文件中

service,dao对象定义在spring的配置文件中,让spring管理这些对象。

springmvc容器和spring容器是有关系的,关系已经确定好了
springmvc容器是spring容器的子容器, 类似java中的继承。 子可以访问父的内容
在子容器中的Controller可以访问父容器中的Service对象, 就可以实现controller使用service对象

实现步骤:

3.1 创建数据库

使用springdb的mysql库, 表使用student(id auto_increment, name, age)

3.2 新建maven web项目

3.3 加入依赖

  springmvc,spring,mybatis三个框架的依赖,jackson依赖,mysql驱动,druid连接池
  jsp,servlet依赖

3.4 编写web.xml

1)注册DispatcherServlet ,目的:

​ 1. 创建springmvc容器对象,才能创建Controller类对象。

​ 2. 创建的是Servlet,才能接受用户的请求。

2)注册spring的监听器:ContextLoaderListener,目的: 创建spring的容器对象,才能创建service,dao等对象。

3)注册字符集过滤器,解决post请求乱码的问题。

web.xml

<!--    注册中央调度器-->
    <servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:conf/dispatcherServlet.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>


    <!--    注册监听器-->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:conf/applicationContext.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>


    <!--    注册字符过滤器-->
    <filter>
        <filter-name>characterEncodingFilter</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>
        <init-param>
            <param-name>forceRequestEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>forceResponseEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>characterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

3.5 创建包

​ Controller包, service ,dao,实体类包名创建好。

3.6 配置文件

​ 写springmvc,spring,mybatis的配置文件
1)springmvc配置文件
2)spring配置文件
3)mybatis主配置文件
4)数据库的属性配置文件

数据库的属性配置(jdbc.properties)

jdbc.url=jdbc:mysql://localhost:3306/ssm
jdbc.username=root
jdbc.password=020821

springmvc配置文件(dispatcherServlet)

    <!--  springmvc配置文件,声明controller和其他web相关的对象  -->
    <context:component-scan base-package="com.controller"/>

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
    <mvc:default-servlet-handler/>

    <!--
            1、响应ajax请求,返回json
            2、解决静态资源访问问题
    -->
    <mvc:annotation-driven/>
    <mvc:resources mapping="/images/**" location="/images/"/>

spring配置文件(applicationContext.xml)

<!--spring配置文件 ,声明service,dao,工具类等对象-->
    <context:property-placeholder location="classpath:conf/jdbc.properties"/>
    <!--    声明数据源,链接数据库-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

    <!--    SqlSessionFactoryBean创建SqlSessionFactory对象-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="configLocation" value="classpath:conf/mybatis.xml"/>
    </bean>
    <!--声明mybatis扫描器,创建dao对象-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
        <property name="basePackage" value="com.dao"/>
    </bean>

    <!--    声明Service的注解@Service所在的位置-->
    <context:component-scan base-package="com.service"/>

mybatis主配置文件(mybatis.xml)

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!--    设置日志-->
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>
    <typeAliases>
        <package name="com.domain"/>
    </typeAliases>
    <!--    指定其他mapper文件的位置
            找到其他文件中的sql语句
    -->
    <mappers>
        <!--告诉 mybatis 要执行的 sql 语句的位置,可以有多个mapper文件。
            使用mapper的resource属性指定mapper文件的路径。
            这个路径是从target/classes路径开始的。
            1、resource = “mapper文件的路径,使用 / 分割路径”。
            一个mapper resource 指定一个mapper文件。
        -->
<!--        <mapper resource="com/dao/StudentDao.xml"/>-->
        <package name="com.dao"/>
    </mappers>
</configuration>

3.7 写代码

​ dao接口和mapper文件, service和实现类,controller, 实体类。

3.8 写jsp页面

略。

第四章 SpringMVC核心技术

4.1 请求转发

​ 1、处理器方法返回 ModelAndView 时,需在 setViewName()指定的视图前添加 forward:,且 此时的视图不再与视图解析器一同工作,这样可以在配置了解析器时指定不同位置的视图。

​ 2、 视图页面必须写出相对于项目根的路径。forward 操作不需要视图解析器。 处理器方法返回 String,在视图路径前面加入 forward: 视图完整路径。

    @RequestMapping(value = {"/forWard.do"}, method = RequestMethod.POST)
    public ModelAndView doSome(String name, Integer age) {
        System.out.println("name = " + name + ", age = " + age);
        ModelAndView mv = new ModelAndView();
        mv.addObject("name", name);
        mv.addObject("age", age);
        mv.setViewName("forward:/WEB-INF/view/show.jsp");
        return mv;
    }

4.2 请求重定向

​ 在处理器方法返回的视图字符串的前面添加 redirect:,则可实现重定向跳转。

框架对重定向的操作:

框架会把Model中的简单类型的数据,转为String使用,作为hello.jsp的e请求参数使用。
	目的是在于doRedirect和hello.jsp 两次请求之间的传递数据。

forWard特点:不和视图解析器一同使用,就当项目中没有视图解析器。

    @RequestMapping(value = {"/doRedirect.do"}, method = RequestMethod.POST)
    public ModelAndView doRedirect(String name, Integer age) {
        System.out.println("name = " + name + ", age = " + age);
        ModelAndView mv = new ModelAndView();
        mv.addObject("name", name);
        mv.addObject("age", age);
        mv.setViewName("redirect:/show.jsp");
        return mv;
    }

param对象:获取地址栏的参数。
<p><h3>doSome传过来的参数 name = ${param.name}</h3></p>
<p><h3>doSome传过来的参数 age= ${param.age}</h3></p>

4.3 异常处理

SpringMVC 框架处理异常的常用方式:使用@ExceptionHandler 注解处理异常。

异常处理基本步骤:

1、新建Maven项目
2、加入依赖
3、新建一个自定义异常类MyUserException,再定义它的子类NameException,AgeException
4、在controller抛出NameException,AgeException
5、创建一个普通类,作用全局的异常处理类
	1)在类的上面加入@ControllerAdvice
	2)在类中定义方法,方法的上面加入@ExceptionHandler
6、创建处理异常的视图页面
7、创建springmvc的配置文件
	1)组件扫描器,扫描@Controller注解
	2)组件扫描器,扫描@ControllerAdvice所在的包名。
	3)声明注解驱动
4.3.1 自定义异常类
public class AgeException extends Exception {
    public AgeException() {
        super();
    }

    public AgeException(String message) {
        super(message);
    }
}
public class NameException extends MyUserException{
    public NameException() {
        super();
    }

    public NameException(String message) {
        super(message);
    }
}
4.3.2 在controller抛出异常
    @RequestMapping(value = {"/some.do"}, method = RequestMethod.POST)
    public ModelAndView doSome(String name, Integer age) throws AgeException, NameException {
        System.out.println("name = " + name + ", age = " + age);
        if (age == null || age > 120) {
            throw new AgeException("年龄太大!!");
        }
        if (!"邓进".equals(name)) {
            throw new NameException("姓名不正确!!");
        }
        ModelAndView mv = new ModelAndView();
        mv.addObject("msg", "欢迎使用springmvc做web开发");
        mv.addObject("fun", "执行的是doSome方法");
        mv.addObject("name", name);
        mv.addObject("age", age);
        mv.setViewName("forward:/WEB-INF/view/show.jsp");
        return mv;
    }
4.3.3 创建异常处理类
/**
 * @author kangkang
 * @ControllerAdvice : 控制器增强(也就是说给控制器增加功能,--异常处理功能)
 * 位置:在类的上面
 * 特点:必须让框架知道这个注解所在的包名,需要在springmvc配置文件声明组件扫描器
 * 指定@ControllerAdvice所在的包名
 */
@ControllerAdvice
public class GlobalExceptionHandler {
    /**
     * 处理异常的方法和控制器方法的定义一样,可以有多个参数,可以有ModelAndView,String ,void 对象类型的返回值.
     * 形参:Exception,表示Controller中抛出的异常对象.
     * 通过形参可以获取发生的异常信息.
     */
    @ExceptionHandler(value = NameException.class)
    public ModelAndView doNameException(Exception exception) {
        ModelAndView mv = new ModelAndView();
        mv.addObject("msg", "当前用户只能是用户[ 邓进 ]能够登录");
        mv.addObject("ex", exception);
        mv.setViewName("nameError");
        return mv;
    }

    /**
     * @param exception
     * @return
     */
    @ExceptionHandler(value = AgeException.class)
    public ModelAndView doAgeException(Exception exception) {
        ModelAndView mv = new ModelAndView();
        mv.addObject("msg", "你的年龄不能大于120或为空!!");
        mv.addObject("ex", exception);
        mv.setViewName("ageError");
        return mv;
    }

    /**
     * 处理其他异常信息
     * 除开NameException和AgeException之外的异常信息
     */
    @ExceptionHandler
    public ModelAndView doOtherException(Exception exception) {
        ModelAndView mv = new ModelAndView();
        mv.addObject("msg", "这是其他的异常!");
        mv.addObject("ex", exception);
        mv.setViewName("defaultError");
        return mv;
    }
}

4.3.4 创建springmvc配置文件
<!-- 关键声明 -->
<!-- 	1)组件扫描器,扫描@Controller注解 -->
    <context:component-scan base-package="controller"/>

<!--   2)组件扫描器,扫描@ControllerAdvice所在的包名 -->
	<context:component-scan base-package="handler"/>

<!--   3)声明注解驱动 -->
	<mvc:annotation-driven/>

4.4 拦截器

SpringMVC 中的 Interceptor 拦截器是非常重要和相当有用的,它的主要作用是拦截指定的用户请求,并进行相应的预处理与后处理。

拦截器是全局的,可以对多个Controller做拦截。
一个项目中可以有0个或多个拦截器。他们在一起拦截用户的请求。
拦截器常用在:用户登录处理,权限检查,记录日志。
4.4.1 实现步骤
1)新建maven项目
2)加入依赖
3)创建controller类
4)创建一个普通类,作为拦截器使用
	1.实现HandlerInterceptor接口
	2.实现接口中的三个方法
5)创建springmvc的配置文件
	1.组件扫描器,扫描@Controller注解
	2.声明拦截器,并指定拦截器的请求uri地址。	
4.4.2 实现接口
public class MyInterceptor implements HandlerInterceptor {}
4.4.3 三个方法

preHandler()

    /**
     * 返回值boolean
     重要:
     	是整个项目的入口,门户。当preHandler返回true 请求可以被处理
     	当preHandler返回false,请求到此方法就截止。
     * <p>
     * 特点:
     * 1、方法在控制器方法之前先执行的,用户的请求首先到达此方法。
     * <p>
     * 2、在这个方法中可以获取请求的信息,验证请求是否符合要求,可以验证用户是否登录,验证用户是否有权限访问某个链接地址(url)
     * 如果验证失败,可以截断请求,请求不能被处理
     * 如果验证成功,可以放行请求,此时控制器方法才能执行。
     *
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("拦截器的MyInterceptor的preHandler()方法");
        return true;
    }

postHandler()

    /**
     * 特点:
     * 1、在处理器方法之后执行的
     * 2、能够获取到处理器方法的返回值ModelAndView,可以修改ModelAndView中的数据和视图,可以影响到最后的执行结果。
     * 3、主要是对原来的执行结果做二次修正。
     *
     * @param request
     * @param response
     * @param handler      被拦截的处理器对象MyController
     * @param modelAndView 处理器方法的返回值
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("拦截器的MyInterceptor的postHandler()方法");
    }

afterCompletion()

    /**
     * 最后执行的方法
     * 特点:
     *      1、在请求处理完成后执行的。框架中规定是当你的视图处理完成后,对视图执行了forward,就认为请求处理完成。
     *      2、一般做资源回收工作的,程序请求过程中创建了一些对象,在这里可以删除,把占用的内存回收。
     * @param request
     * @param response
     * @param handler 被拦截器拦截的处理器对象
     * @param ex 程序中发生的异常
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("拦截器的MyInterceptor的afterCompletion()方法");
    }
4.4.4 声明拦截器
<!--    声明拦截器-->
    <mvc:interceptors>
        <mvc:interceptor>
            <!--指定拦截的请求uri地址
                path:就是uri地址,可以使用通配符 **
                ** : 表示任意的字符,文件或者多级目录和目录中的文件。

            -->
            <mvc:mapping path="/**"/>
            <!--            声明拦截器对象-->
            <bean class="handler.MyInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>
4.4.5 多个拦截器

springmvc配置文件

    <!--    声明拦截器-->
    <mvc:interceptors>

        <!--            声明第一个拦截器-->
        <mvc:interceptor>
            <!--指定拦截的请求uri地址
            path:就是uri地址,可以使用通配符 **
            ** : 表示任意的字符,文件或者多级目录和目录中的文件。

            -->
            <mvc:mapping path="/**"/>
            <!--            声明拦截器对象-->
            <bean class="handler.MyInterceptor01"/>

        </mvc:interceptor>

        <!--        声明第二个拦截器-->
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <bean class="handler.MyInterceptor02"></bean>
        </mvc:interceptor>
    </mvc:interceptors>

多个拦截器执行顺序

按照配置文件中的拦截器配置先后顺序,可以联想递归的思想进行理解。

111111-拦截器的MyInterceptor的preHandler()方法
222222-拦截器的MyInterceptor的preHandler()方法
执行MyController执行的doSome方法
222222-拦截器的MyInterceptor的postHandler()方法
111111-拦截器的MyInterceptor的postHandler()方法
222222-拦截器的MyInterceptor的afterCompletion()
111111-拦截器的MyInterceptor的afterCompletion()方法

注意:

​ 1、只有当多个拦截器中的preHandler都返回true时才能成功访问MyController方法。

4.5 拦截器与过滤器的区别

1、过滤器是servlet中的对象,拦截器是框架中的对象。
2、过滤器是实现Filter接口的对象,拦截器是实现HandlerInterceptor。
3、过滤器是用来设置request、response的参数,属性的,侧重对数据过滤的。
	拦截器是用来验证请求的,能截断请求。
4、过滤器是在拦截器之前先执行的。
5、过滤器是Tomcat服务器创建的对象,拦截器是springmvc中创建的对象。
6、过滤器是一个执行时间点。
	拦截器有三个执行时间点。
7、过滤器可以处理jsp,js,html等等。
	拦截器是侧重拦截对Controller的对象。
	如果你的请求不能被DispathcerServlet(中央调度器)接收,这个请求不会执行拦截器内容。

8、拦截器拦截普通类方法的执行,过滤器过滤servlet请求

4.6 springmvc执行流程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FIZHs1Y4-1648823073952)(C:\Users\kangkang\AppData\Roaming\Typora\typora-user-images\image-20220212221408305.png)]

4.6.1 执行流程分析
(1)浏览器提交请求到中央调度器
(2)中央调度器直接将请求转给处理器映射器。
(3)处理器映射器会根据请求,找到处理该请求的处理器,并将其封装为处理器执行链后
返回给中央调度器。
(4)中央调度器根据处理器执行链中的处理器,找到能够执行该处理器的处理器适配器。
(5)处理器适配器调用执行处理器。
(6)处理器将处理结果及要跳转的视图封装到一个对象 ModelAndView 中,并将其返回给
处理器适配器。
(7)处理器适配器直接将结果返回给中央调度器。
(8)中央调度器调用视图解析器,将 ModelAndView 中的视图名称封装为视图对象。
(9)视图解析器将封装了的视图对象返回给中央调度器
(10)中央调度器调用视图对象,让其自己进行渲染,即进行数据填充,形成响应对象。
(11)中央调度器响应浏览器。
处理器映射器的作用:
	根据请求,从springmvc容器对象中获取处理器对象(MyConytroller controller = ctx.getBean("some.do"))框架把找到的	处理器对象放到一个叫做处理器执行链(HandlerExecutionChain)的类中保存。
HandlerExecutionChain:
						类中保存着,1、处理器对象(MyController);
								2、项目中所有的拦截器List<HandlerInterceptor> interceptorList
	
DispatcherServlet把上面的HandlerExecutionChain中处理器对象交给了处理器适配器对象(多个)
处理器适配器:
			springmvc框架中的对象,需要实现HandlerAdapter接口。
处理器适配器作用:执行处理器方法(调用MyController.doSome()得到返回值ModleAndView)
DispatcherServlet把3中获取的ModelAndView交给了视图解析器对象。
视图解析器:
			springmvc中的对象,需要实现ViewResoler接口(可以有多个)
视图解析器作用:
			组成视图完整路径,使用前缀,后缀。并创建View对象。
			View是一个接口,表示视图的,在框架中jsp,html不是string表示,而是使用View和它的实现类表示视图。
            InternalResourceView:视图类,表示jsp文件,视图解析器ViewResoler会创建InternalResourceView类对象。
				这个对象的里面,有一个属性url = /WEB_INF/view/sho
DispatcherServlet把刚刚创建的View对象获取到,调用View类自己的方法,把Model数据放入到request作用域。执行对象视图的forward。请求结束。

648823073952)]

4.6.1 执行流程分析
(1)浏览器提交请求到中央调度器
(2)中央调度器直接将请求转给处理器映射器。
(3)处理器映射器会根据请求,找到处理该请求的处理器,并将其封装为处理器执行链后
返回给中央调度器。
(4)中央调度器根据处理器执行链中的处理器,找到能够执行该处理器的处理器适配器。
(5)处理器适配器调用执行处理器。
(6)处理器将处理结果及要跳转的视图封装到一个对象 ModelAndView 中,并将其返回给
处理器适配器。
(7)处理器适配器直接将结果返回给中央调度器。
(8)中央调度器调用视图解析器,将 ModelAndView 中的视图名称封装为视图对象。
(9)视图解析器将封装了的视图对象返回给中央调度器
(10)中央调度器调用视图对象,让其自己进行渲染,即进行数据填充,形成响应对象。
(11)中央调度器响应浏览器。
处理器映射器的作用:
	根据请求,从springmvc容器对象中获取处理器对象(MyConytroller controller = ctx.getBean("some.do"))框架把找到的	处理器对象放到一个叫做处理器执行链(HandlerExecutionChain)的类中保存。
HandlerExecutionChain:
						类中保存着,1、处理器对象(MyController);
								2、项目中所有的拦截器List<HandlerInterceptor> interceptorList
	
DispatcherServlet把上面的HandlerExecutionChain中处理器对象交给了处理器适配器对象(多个)
处理器适配器:
			springmvc框架中的对象,需要实现HandlerAdapter接口。
处理器适配器作用:执行处理器方法(调用MyController.doSome()得到返回值ModleAndView)
DispatcherServlet把3中获取的ModelAndView交给了视图解析器对象。
视图解析器:
			springmvc中的对象,需要实现ViewResoler接口(可以有多个)
视图解析器作用:
			组成视图完整路径,使用前缀,后缀。并创建View对象。
			View是一个接口,表示视图的,在框架中jsp,html不是string表示,而是使用View和它的实现类表示视图。
            InternalResourceView:视图类,表示jsp文件,视图解析器ViewResoler会创建InternalResourceView类对象。
				这个对象的里面,有一个属性url = /WEB_INF/view/sho
DispatcherServlet把刚刚创建的View对象获取到,调用View类自己的方法,把Model数据放入到request作用域。执行对象视图的forward。请求结束。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿姨洗铁路℡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值