SpringMVC入门

    技术2022-07-12  69

    一、SpringMVC概述

    SpringMVC是Spring中的一个组件,SpringMVC用于web层,相当于controller(等价于传统的servlet和struts的action,或者hendler),用来处理用户请求。 同时,SpringMVC也是一种基于Java的实现MVC设计模式的请求驱动类型的轻量级Web框架,使用了MVC架构模式的思想,将web层进行职责解耦。举个例子,用户在地址栏输入http://网站域名/login,那么springmvc就会拦截到这个请求,并且调用controller层中相应的方法,(中间可能包含验证用户名和密码的业务逻辑,以及查询数据库操作,但这些都不是springmvc的职责),最终把结果返回给用户,并且返回相应的页面(当然也可以只返回json/xml等格式数据)。springmvc就是做前面和后面过程的活,与用户打交道!!springmvc需要有spring的jar包作为支撑才能跑起来,所以需要Spring的基础。

    总结: SpringMVC作用相当于servlet,但是简化了servlet的复杂操作,将这部分复杂操作交给框架去实现

    二、Springmvc处理流程

    在springmvc的各个组件中,处理器映射器、处理器适配器、视图解析器称为springmvc的三大组件

    以下组件通常使用框架提供实现:

    DispatcherServlet:前端控制器 用户请求到达前端控制器,它就相当于mvc模式中的c,dispatcherServlet是整个流程控制的中心,由它调用其它组件处理用户的请求,dispatcherServlet的存在降低了组件之间的耦合性。HandlerMapping:处理器映射器 HandlerMapping负责根据用户请求url找到Handler即处理器,springmvc提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。Handler:处理器 Handler 是继DispatcherServlet前端控制器的后端控制器,在DispatcherServlet的控制下Handler对具体的用户请求进行处理。 由于Handler涉及到具体的用户业务请求,所以一般情况需要程序员根据业务需求开发Handler。HandlAdapter:处理器适配器 通过HandlerAdapter对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。ViewResolver:视图解析器 View Resolver负责将处理结果生成View视图,View Resolver首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户。

    开发流程:

    导入相应的依赖在web.xml中配置SpringMVC的核心控制器在web.xml中指定配置文件的路径在springmvc的配置文件中,扫描具有注解的类,同时使springmvc的注解生效在controller类上添加注解@Controller给该类中的方法添加@RequstMapping注解,表示请求地址

    三、SpringMVC入门案例(注解版)

    第一步:新建项目

    在 IDEA 中新建 Spring MVC 项目(IDEA会自动帮我们导入SpringMVC所需要的jar包),并且取名为 【HelloSpringMVC】,点击【Finish】

    第二步:修改 web.xml

    web.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前端控制器DispatcherServlet(固定写法) --> <servlet> <servlet-name>springDispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- SpringMVC的配置文件所在的位置和名称(默认在src下,如果是maven,则是在resource中) --> <init-param> <param-name>contextConfigLocation</param-name> <!--框架进行转发规则的定义文件--> <param-value>classpath:springmvc.xml</param-value> </init-param> <!--表示服务器一启动,最优先加载前端控制器DispatcherServlet--> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springDispatcherServlet</servlet-name> <!-- SpringMVC拦截所有请求,再进行转发 --> <url-pattern>/</url-pattern> </servlet-mapping> <!-- 配置编码级过滤器,防止中午乱码 --> <!-- 编码级过滤器 --> <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> </filter> <filter-mapping> <filter-name>characterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>

    把<url-pattern>元素的值改为 *.form(或者其他的名字),表示要拦截请求以.form结尾的请求,并交由Spring MVC的后台控制器来处理,改完之后:

    <servlet-mapping> <servlet-name>dispatcher</servlet-name> <url-pattern>*.form</url-pattern> </servlet-mapping>

    说明:

    方式一: *.form , 可以访问以.form结尾的地址,由DispatcherServlet进行解析。此方法最简单,不会导致静态资源(jpg,js,css)被拦截。【开发中经常使用】方式二:/ ,所有访问的地址都由DispatcherServlet进行解析,此方法可以实现REST风格的url,很多互联网类型的应用使用这种方式。但是此方法会导致静态文件(jpg,js,css)被拦截后不能正常显示,所以对静态文件的解析需要配置不让DispatcherServlet进行解析。【开发中建议使用】

    第三步:创建springmvc.xml文件

    在src目录下创建SpringMVC的配置文件springmvc.xml,并加入如下代码

    <?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" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.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/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!-- 配置扫描包,告诉SpringMVC被注解的class都在哪个包下 --> <context:component-scan base-package="com.myw.controller"></context:component-scan> <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy> <!-- 使springmvc的注解生效 --> <mvc:annotation-driven ></mvc:annotation-driven> <!--静态资源过滤器 --> springmvc默认不支持静态资源(html/css/js/img..),所以需要配置静态资源过滤器 <!-- location:"/"要过滤静态资源路径 mapping="/**"表示要过滤哪些内容 --> <mvc:resources location="/" mapping="/**"></mvc:resources> <!-- //配置处理器映射器 <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping" /> //配置处理器映射器 <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping" /> --> <!-- 直接配置处理器映射器和处理器适配器比较麻烦,可以使用注解驱动annotation-driven来加载 --> <!-- //配置视图解析器,告诉SpringMVC在网站的哪个目录下能找到jsp文件(现在一般不用jsp,所以这一段一般可以不写) <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/views/"></property> <property name="suffix" value=".jsp"></property> </bean> --> </beans>

    第四步:编写接受请求的控制器

    相当于编写servlet

    import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; @Controller public class HelloWorld { /** * 1. 使用RequestMapping注解来映射请求的URL,写在方法上面,一个请求对应一个方法 * 2. 使用ResponseBody注解(Ajax常用此法返回值,如果是其他对象,则返回json对象) * 当返回值是String,并且方法上方有此注解时,返回的字符串将不在被解析为springmvc的视图(即jsp文件),会被 * 直接以字符串展示在浏览器里 */ @RequestMapping("helloworld") @ResponseBody public String hello(){ System.out.println("hello world"); return "success"; } }

    注:

    @Controller 注解: 很明显,这个注解是用来声明控制器的,但实际上这个注解对 Spring MVC 本身的影响并不大。

    @RequestMapping 注解: 很显然,这就表示路径 helloworld 会映射到该方法上

    第五步:开启tomcat

    修改端口号为http的默认端口80(非必须),并且找到安装好的tomcat(Application server)

    修改项目的虚拟路径名

    第六步:准备前端html页面,通过ajax跳转请求并获取相应的返回结果

    $.ajax({ url:"helloworld", type:"post", //data:{"username":username,"password":password}, //dataType:"json", success:function (result){ console.log(result); } });

    四、 SpringMVC映射规则

    二级映射

    在类上和方法上同时注解@RequestMapping,相当于地址栏里有两级的地址

    import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; @Controller @RequestMapping("one") public class TestController { @RequestMapping("two") public String test(){ return "index"; } } //如上注解后,映射地址为:http://localhost:8080/xx/one/two

    参数绑定的含义

    所谓的参数绑定,就是怎么样获取到前台页面传过来的值,通常是跟据参数名(key)来获取值;

    //页面端提交请求的程序 $.post("../hc.v", { name : "shoji", price : "8888" }, function(d) { alert(d); } ) //后台响应上面ajax的post请求的代码 //通过两段代码里“name”和“price”的相同,把“shouji”和“8888”传到hc方法里 //问号传值的方式同样适用 ?name=shoji&price=88882. ... //这里一般会添加@Responsebody或者在类上添加 @RequestMapping("hc.v") @Responsebody public String hc(String name,String price){ return "test"; } ...

    映射方法的返回值类型

    @ResponseBody注解

    当返回值是String,并且方法上方有此注解时,返回的字符串将不在被解析为springmvc的视图(即jsp文件),会被直接以字符串展示在浏览器里(如果是map集合或者pojo类这些有键值对的对象时,则转化为json字符串返回) @RequestMapping("/test") @ResponseBody public String hhh() { return "first"; } //first将被ajax接收

    注:

    这个注解如果这个类中,全是返回ajax请求的方法,则直接在类上写@ResponseBody即可,和@Controller可以合并缩写为@RestController

    @RestController public class HelloSpringMVC{ @RequestMapping("/test") public String hhh() { return "first"; } }

    五、完整登录实例

    这里写一个登录的实例,没有用Mybatis所以没有用Dao层,直接默认用户名为admin,密码为123456

    //先写pojo类 package com.myw.pojo; public class User { private Integer id; private String account; private String password; public User() { super(); } public User(String account, String password) { this.account = account; this.password = password; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getAccount() { return account; } public void setAccount(String account) { this.account = account == null ? null : account.trim(); } public String getPassword() { return password; } public void setPassword(String password) { this.password = password == null ? null : password.trim(); } }

    再写service层(虽然没有Dao层,但是所有的逻辑验证都应该放在service层)

    //service的接口 package com.myw.service; import com.myw.pojo.User; import java.util.Map; public interface IUserService { /** * 如果匹配成功,则返回user,否则返回null * @return */ public User login(String account, String password); } //service的实现类(因为没有用mybatis所以mapper包为空) package com.myw.service.Impl; //import com.myw.mapper.UserMapper; import com.myw.pojo.User; import com.myw.service.IUserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class UserServiceImpl implements IUserService { //@Autowired //private UserMapper um; @Override public User login(String account, String password) { //User user = um.selectByUserName(username); //如果用户名存在并且密码匹配 if("admin".equals(account) && "123456".equals(password)){ return new User(account,password); } return null; } }

    写web层

    package com.myw.web; import java.util.Map; import com.myw.pojo.User; import com.myw.service.IUserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpSession; @RestController //现在jsp有点过时,一般是用ajax,所以直接使用RestController注解 public class UserController { @Autowired private IUserService us; @RequestMapping("login") public Map<String, Object> login(User user, HttpSession session){ User u = us.login(user.getAccount(),user.getPassword()); Map<String,Object> map = new HashMap<>(); //如果用户成功登录,则将其添加到session中 if(u != null){ session.setAttribute("user",u); map.put("code",1); }else{ map.put("code",0); } return map; } }

    前端部分:

    //index.html(如果前端页面的名字和请求名一样,则会无法显示页面) <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>SpringMVCDemo</title> <script src="js/jquery.js"></script> </head> <body> 用户名:<input type="text" id="account"/> 密码:<input type="password" id="password"/> <input type="button" value="登录" onclick="login()"/> </body> <script> function login(){ let account = $("#account").val(); let password = $("#password").val(); $.ajax({ url:"login", type:"post", data:{"account":account,"password":password}, dataType:"json", success:function (result){ console.log(result); if(result.code==0){ alert("用户名或密码错误"); //location.href = "register.html"; }else{ alert("登录成功"); } } }); } </script> </html>
    Processed: 0.011, SQL: 9