SpringMVC基础篇:第一个MVC程序和细节分析

简介: SpringMVC基础篇:第一个MVC程序和细节分析


第一章:编码开发

一:思路分析

作为SpringMVC来讲他的核心就是控制器。控制器在之前我们了解过Servlet,我们现在通过Servlet的开发推导出SringMVC的开发。

我们编写一个类,这个类需要extends HttpServlet继承之后,我们重写其中的service方法,方法的参数时request和response。然后我们在其中进行接收请求参数、业务处理、页面跳转等操作。这就是我们需要编码的细节。

代码写完之后,我们需要在web.xml当中配置一个servlet标签:

servlet-name:当中起一个名字,唯一就行。

servlet-class:带包带类,实际上就是类的限定名称。

与之对应的我们还需要配置一个servlet-mapping标签,作用就是对外暴露我们这个Servlet对应的URL。

servlet-name:跟上边保持一致

url-pattern:一个URL

http://localhost:8989/basic/firstServlet

这是一个请求的完成的URL,我们在地址栏当中输入这个路径之后,基于ip+端口+应用名。后边的/firstServlet找到对应的url-pattern,进而找到对应的servlet-name进而找到对应的servlet-class。这就是我们servlet开发的开发方式。

对于SpringMVC来讲,他所提供的控制器就是为了替换原生Servlet的,他们在开发过程中主题思想是保持一致的。SpringMVC的控制器一定会简化现有的MVC的开发的。

SpringMVC的控制器在开发过程当中,是不需要继承父类或者实现接口这样的要求,只需要在类上边添加一个@Controller注解(上述图右)注解可以起到接口这样约定性的作用,继承父类或者实现接口这样的方式被注解取代掉了。这就是二者在开发类上边的区别关系。

在Servlet当中我们只能写Service方法,但是在SpringMVC当中对应的名字,他的方法名字是可以随便写的。对于SpringMVC的方法的返回值不再是void了,而是Spring就是跳转路径。

作为SpringMVC来中的Controller来将他如何指定他的URL呢,只需要在方法上加一个注解@RequestMapping即可。这个注解当中的路径就是他对应的URI用户在通过地址栏访问的时候就是在方法上写的地址的内容。

这个和Basic是一致的。举例来讲:Http:localhost:8989/spring-mvc1/firstController即可。

基本开发流程:

1:开发一个类在类上加Controller注解

2:提供一个控制器方法。参数是:HttpServletRequest,HttpServletResponse,返回值是String的,同事加入@RequestMapping注解定义请求路径。

3:在控制方法中,完成核心开发功能,把对应的JSP页面的路径作为返回值返回。

二:SpringMVC程序编码

在我们的IDEA当中我把相关的内容关掉。

后端代码:

@Controller
public class FirstController {
    public FirstController() {
        System.out.println("FirstController.FirstController");
    }
    @RequestMapping("/first")
    //方位这个控制器方法的路径是first
    public String first(HttpServletRequest request, HttpServletResponse response){
        System.out.println("FirstController.first");
        //跳转到根下边的这个jsp
        return "/result.jsp";
    }
}

JSP代码

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Result</title>
</head>
<body>
   <h1>this is result jsp</h1>
</body>
</html>

浏览器访问地址:

http://localhost:8989/basic/first

注意:必须要进行@Controller注解的扫描。

三:控制器提供多个服务方法

作为控制器来讲,Servlet当中是不允许一个控制器提供多个服务方法的。在Servlet当中一个控制器只能提供一个方法。这是因为在Servlet当中必须实现接口规定的service(HttpServletRequest,HttpServletResponse)方法,一个类中只能实现一次,所以一个类当中只能有一个服务方法。在Servlet想要提供服务就之能写Servlet接口提供的规定。所以,我们基于Servlet只能基于以下的代码结构:

作为SpringMVC的控制器一个类当红中可以提供多个对外服务的方法的。究其原因是因为SpringMVC控制器当中的服务方法对于方法名是没有任何要求的:

@Controller
public class FirstController {
    public FirstController() {
        System.out.println("FirstController.FirstController");
    }
    @RequestMapping("/first")
    public String first(HttpServletRequest request, HttpServletResponse response){
        System.out.println("FirstController.first");
        return "/result.jsp";
    }
    // http://localhost:8989/basic/suns/second
    @RequestMapping(value="suns/second")
    public String second(HttpServletRequest request,HttpServletResponse response){
        System.out.println("FirstController.second");
        return "/result.jsp";
    }
}

我们写Value等于这种形式没啥区别,如果注解当中只写一个属性,且属性为value,则value可省略。

四:注意事项

SpringMVC开发过程中习惯上把控制器称之为Controller,SpringMVC内部也把开发的控制器也叫做Handler因为后续我们查看源码的过程当中经常看到Handler…等等各种各样的说法。

第二章:细节分析

一:控制器创建次数

作为Servlet来讲,他对应的控制器被创建的次数是几次呢?一中Servlet只会被Tomcat创建一次。请求过来之后,Tomcat只会创建一次这个对象。所以我们常说:Servlet是单实例的(注意这个不是单例设计模式)

SpringMVC的控制器被Spring创建的次数是尊询Spring的规则,可以只创建一次,也可以创建多次。默认可以创建一次,也可以去创建多次。如果想创建多次,我们可以加一个@Scope注解来设定。如果是@Scope是prototype的话,那么一次请求就会对应创建一个Controller对象。

默认SpringMVC的Controller只会被创建一次,存在线程安全的问题。如果这里边有成员变量,并且这里边成员变量是线程不安全的话,就会有问题。

二:@RequestMapping注解

该注解核心作用就是为控制器方法提供外部访问的URI路径。服务器就可以将用户URL当中的URL同注解当中的路径进行匹配来让客户访问对应的服务。这个工作是由RequestMappingHandlerMapping来处理的,对方法上添加这个注解的服务进行一一扫描,来进行服务注册。

1:路径分隔符/可省略

SpringMVC当中“/first”当中的/是可以省略的。如果是多级路径,第一个/是可以省略的。

2:一个控制器方法上指定多个注解

@Controller
//@Scope("singleton")
//@Scope("prototype")
public class FirstController {
    public FirstController() {
        System.out.println("FirstController.FirstController");
    }
    //@RequestMapping("/first")
    //@RequestMapping("first")
    @RequestMapping(value = {"/first","/third"})
    public String first(HttpServletRequest request, HttpServletResponse response){
        System.out.println("FirstController.first");
        return "/result.jsp";
    }
    // http://localhost:8989/basic/suns/second
    @RequestMapping(value="suns/second")
    public String second(HttpServletRequest request,HttpServletResponse response){
        System.out.println("FirstController.second");
        return "/result.jsp";
    }
}

3:类上的@RequestMapping

可以在类上加注解,这就让URL上多加一个层级而已。

http://localhost:8989/basid/user/addUser

http://localhost:8989/basid/user/deteleUser

@Controller
@RequestMapping("/user")
public class UserController {
    @RequestMapping("/addUser")
    public String addUser() {
        System.out.println("UserController.addUser");
        return "/result.jsp";
    }
    @RequestMapping("/deleteUser")
    public String deleteUser() {
        System.out.println("UserController.deleteUser");
        return "/result.jsp";
    }
}

类上@RequestMapping设计意图:

为什么SpringMVC设计的过程当中让我们在类上加这样的一个注解呢?

为了统一服务,我们在使用的过程中,会把一组相关的操作放到同一个控制器当中。用户Controller负责用户的事,账户Controller负责账户的事。采用了这样的设计之后,用户的URL就会很规范,在访问的路径上也能体现出模块化。

第三章:请求方式

一:回顾请求方式

所谓的请求方式就是JavaWeb当中讲的get和post请求等等。

二:Post和Get请求的区别

1:两种请求提交数据的区别

1:Get请求通过请求行地址栏提交数据,数据明文提交(QueryString),不安全提交的数据量小不能超过2048个字节(2MB),这是上线,具体多少还得看

2:Post请求:通过请求体提交数据,密文提交,这里不是说会加密,而是说一般用户不可见,相对安全,理论上是没有大小限制的。

1:GET请求:通过请求行(地址栏)提交数据(QueryString),明文数据提交,不安全,提交的数据量小(不能超过2048字节),当然我们所说的2048字节是上限值,最终多少还得看浏览器的实现。

http://localhost:8989/basic/user/queryuser?name=sunshuai&password=123456

上述就是使用Get请求提交的一个形式,我们会在URL后边打一个问号,问号后边的都是QueryString这个也都是我们提交的明文数据。

2:POST请求:通过请求体提交数据,密文提交(不是加密,指的是一般用户不可见),相对安全,这个是走请求体提交数据,提交数据量大(理论上没有限制)

原来我们解决中文字符集乱码的问题的时候GET和Post解决方式是不一致的,因为提交数据的位置不一样。

2:两种请求发起方式的区别

三:@RequestMapping限定用户请求方式

1:默认支持所有请求方式

默认情况下:@RequestMapping注解,接受所有请求方式的访问 (Post,Get,…)

2:限定固定请求方式

通过@RequestMapping注解可以限定,某个控制器方法只接受特定的请求方式

@RequestMapping(method={RequestMethod.POST})

public String xxx(HttpServletRequest,HttpServletResponse)

@RequestMapping(method={RequestMethod.GET))

public String xxx(HttpServletRequest,HttpServletResponse)

3:同时限定多种请求方式

@RequestMapping注解可以同时限定多种请求方式的访问

@RequestMapping(method={RequestMethod.GET,RequestMethod.POST))

public String xxx(HttpServletRequest,HttpServletResponse)

4:发起不支持的请求方式

当用户发起了@RequestMapping不支持的请求操作

SpringMVC在服务器端抛出一个405错误 Method Not Allowed

三:@RequestMapping限定其他请求方式

1:Http协议提供了其他请求方式

除常规的POST,GET请求外Http协议还提供了其他的请求方式PUT、DELETE、OPTIONS

2:@RequestMapping也支持其他请求方式

@RequestMapping注解,默认情况下也支持其他请求方式的访问,同时也可以根据需要进行限定@RequestMapping(method={RequestMethod.DELETE)

public String xxx(HttpServletRequest,HttpServletResponse)

3:浏览器对于其他请求方式的支持

除Post,Get这2种请求方式外,其他的请求方式浏览器支持的不好,可以使用专属工具或者库进行测试

4:其他请求方式的响应形式

其他的请求方式,大多数不支持响应视图技术 (JSP,Thymeleaf),只能返回简单字符串或者JSON数据。

第四章:控制器方法的参数

SpringMVC在控制器方法设计的过程中,非常灵活可以多种参数的设置方式,这也叫作数据绑定。

一:代码一

@RequestMapping("/first")
public String first(HttpServletRequest request,HttpServletRespose response){
}

这是我们最长接触的一种方式,这个跟我们Servlet当中代码的写法如出一辙。

二:代码二

@RequestMapping("/first")
public String first(HttpServletRequest request){
}

这种方式在Servlet当中是不允许的因为和service方法不一样。

三:代码三

@RequestMapping("/first")
public String first(HttpServletReponse response){
}

四:代码四

@RequestMapping("/first")
public String first(HttpServletRequest request,HttpServletRespose response,HttpSession session){
}

这段代码当中我们引入了一个新的参数Session它直接作为控制器方法设置进来了。可以简化变成。

Session可以和前两个相互结合出现使用,即都使用或者搭配使用都是可以的。

我们在web开发得时候提到过作用域得概念,作用域涉及到三个对象:HttpServletRequest 、HttpSession 、ServletContext对象

我们在上述的方法中已经能获取到HttpServletRequest 、HttpSession这两个作用域对象了,但是ServletContext是不能作为对象放到控制器方法上作为参数的。

那么我们如何获取ServletContext对象呢?

session.getServletContext();或者request.getSession().getServletContext();即可。

五:代码五

@RequestMapping("/first")
public String first(){
}

这个接口完全是没有任何问题的。

六:控制器方法的参数思考

1:上述五种代码形式,那种更常用

前四种代码中都使用了Servlet的API,都是原有的Servlet当中的对象,这不是一件好事,耦合了ServletAPI之后,切换其他的开发技术之后,那么可就不好改了。

比如,如果我们后续切换到了Spring WebFlex的API,他就彻底废弃了Servlet的API。

前四种的方式最大的问题就在于耦合了Servlet的API。第五种也是不可取的,因为需要形参获取客户端的请求参数。这种空参就改变了这种形式。

第五章:试图解析器

视图解析器解决的是跳转的问题,在我们控制器方法执行完毕之后,我们会提供一个返回值例如:return "/result.jsp"后续SpringMVC执行完控制器功能之后,就会按照路径进行跳转。

一:目前页面跳转存在的问题

1:控制器中的跳转路径与实际视图路径存在耦合

一旦存在耦合就不利于维护。

webapp就是我们所说的这个根。result1.jsp在我们的根下,所以我们就会写成下边这样的路径代码。但是这样就造成了耦合。当我们后续需要对我们的JSP文件换换位置的时候我们就发现我们的这个代码也是需要修改的。

二:视图解析器分析

如何解决这种耦合呢?这就用到了我们马上要学习的另外一个学习内容叫做视图解析器。

通过视图解析器(ViewResolver)就可以解决跳转路径与实际视图路径耦合的问题。

result1.jsp是一直不变化的。也就是我们的文件名是一直不变化的,而我们的路径是可变的。可变的改成配置。

左边这种写死的耦合的形式等于右边配置+不变的名字的这种情况。前边+后边

右边的的定义了前缀和后缀(路径起始和文件后缀)如果改了文件路径,改下前缀配置即可,降低了耦合性。

这个配置内容是在Spring的核心配置文件当中加入的配置。是SpringMVC对于视图解析器的支持。

三:视图解析器代码开发

@RequestMapping("/first")
public String first(HttpServletReponse response){
  return "/result.jsp"
}

后续开发过程中,SpringMVC首先会拿到我们控制器代码当中返回的result,然后将返回的result拼接上前缀和后缀,这样的话就生成了完整的视图路径,然后进行调转。

启动我们的Tomcat进行测试即可。

四:视图解析器注解编程

第六章:SpringMVC配置文件的默认设置

搭建SpringMVC默认开发环境的时候,我们会书写web.xml文件。在里边我们会配置DispacherServlet的名字

还会显示的指示对应的Spring核心配置文件的位置

如果没有显示指定的话,系统会查找默认的配置文件。

SpringMVC默认配置文件的名字和放置路径是:

/WEB-INF/[servlet-name]-servlet.xml

根据上述配置:SpringMVC配置文件的默认名字是

/WEB-INF/dispacher-servlet.xml,这里边的dispacher取得是这个值。

相关文章
|
4月前
|
设计模式 前端开发 JavaScript
Spring MVC(一)【什么是Spring MVC】
Spring MVC(一)【什么是Spring MVC】
|
4月前
|
前端开发 Java 应用服务中间件
SpringMVC基础篇:MVC基础知识
vSpringMVC基础篇:MVC基础知识
|
23天前
|
前端开发 JavaScript Java
MVC框架:SpringMVC(三)
MVC框架:SpringMVC
30 0
|
23天前
|
JSON 前端开发 JavaScript
MVC框架:SpringMVC(二)
MVC框架:SpringMVC
35 0
|
23天前
|
前端开发 Java 应用服务中间件
MVC框架:SpringMVC(一)
MVC框架:SpringMVC
59 0
|
1月前
|
存储 设计模式 前端开发
请解释 Web 应用程序的 MVC(模型-视图-控制器)架构。
【2月更文挑战第26天】【2月更文挑战第89篇】请解释 Web 应用程序的 MVC(模型-视图-控制器)架构。
|
3月前
|
前端开发 Java Spring
【Spring MVC】SpringMVC自动配置
【1月更文挑战第14天】【Spring MVC】SpringMVC自动配置
|
4月前
|
设计模式 前端开发 Java
Spring Boot之Spring MVC的工作原理 以及使用eclipse开发Spring MVC的Web应用实战(附源码)
Spring Boot之Spring MVC的工作原理 以及使用eclipse开发Spring MVC的Web应用实战(附源码)
45 0
|
4月前
|
XML 前端开发 Java
SpringMVC中<mvc:annotation-driven/>标签原理与实践详解
SpringMVC中<mvc:annotation-driven/>标签原理与实践详解
43 0
|
4月前
|
XML 前端开发 JavaScript
SpringMVC中单独配置<mvc:default-servlet-handler/> 导致 Controller失效
SpringMVC中单独配置<mvc:default-servlet-handler/> 导致 Controller失效
75 0