Spring MVC
导入pom.xml依赖
-
Root
<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.3.18</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> </dependencies>
-
模块
<dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> <version>2.2.1-b03</version> </dependency> </dependencies>
1、回顾Servlet
-
创建Maven模块
-
Add Framework Support
-
创建Servlet类
-
继承HttpServlet父类
-
写doGet/doPost方法
-
通过请求转发,实现数据共享
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String method = request.getParameter("method"); if ("add".equals(method)){ request.setAttribute("method","add one data"); }else{ request.setAttribute("method","delete one data"); } request.getRequestDispatcher("hello.jsp").forward(request,response); }
-
-
创建jsp文件
- 获取Servlet传来的数据可以通过EL表达式直接将数据显示
${method}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
从Servlet得到的方法为:${method}
- 传入链接到浏览器测试
http://localhost:8080/hello?method=delete
2、Hello!SpringMVC
运行的时候,要查看lib文件夹是否生成,如果没有生成,在ProjectStructor中,进行如下操作
-
web.xml配置DispatcherServlet
- DispatcherServlet是SpringMVC的核心,称为请求分发器
<!--注册DispatcherServlet--> <servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!--关联SpringMVC的配置文件 springmvc-servlet.xml --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>springmvc-servlet.xml</param-value> </init-param> <!--启动级别-1--> <load-on-startup>1</load-on-startup> </servlet> <!--匹配所有的请求(不包括.jsp)--> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
-
配置DispatcherServlet对应的springmvc-servlet.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--处理器映射器-->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<!--处理器适配器-->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
<!--视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="InternalResourceViewResolver">
<!--前缀-->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!--后缀-->
<property name="suffix" value=".jsp"/>
</bean>
</beans>
- 写HelloController类
public class HelloController implements Controller {
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
//模型和视图
ModelAndView mv = new ModelAndView();
//封装对象,放在ModelAndView中
mv.addObject("msg","HelloSpringMVC");
//封装要跳转的视图,放在ModelAndView中
mv.setViewName("hello"); //要跳转的jsp
return mv;
}
}
- 写jsp文件
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
${msg}
- 将Controller类注册到Spring中
<bean id="/hello" class="com.wjh.controller.HelloController"/>
需要注意的是:
- 写Controller很麻烦,每个方法只能对应一个ModelAndView,每次添加新的视图,都需要创建新方法
- 所以用注解实现更方便
3、注解实现SpringMVC
- 配置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">
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<filter>
<filter-name>encoding</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>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
-
配置springmvc-servlet.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:context="http://www.springframework.org/schema/context" 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 https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!--自动扫包,将指定包下的注解生效--> <context:component-scan base-package="com.wjh.controller"/> <!--让SpringMVC不处理静态资源 如.css .html .js --> <mvc:default-servlet-handler/> <!--支持mvc驱动,注入DefaultAnnotationHandlerMapping和AnnotationMethodHandlerAdapter--> <mvc:annotation-driven/> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver"> <property name="prefix" value="/WEB-INF/jsp/"/> <property name="suffix" value=".jsp"/> </bean> </beans>
-
写Controller类 通过注解实现
-
@Controller表示继承Controller,声明类是一个控制器
-
@RequestMapping表明请求的路径
-
Model来分享数据
-
return的字符串就是jsp的文件名
@Controller @RequestMapping("/h1") public class HelloController { @RequestMapping("/hello") public String hello(Model model){ model.addAttribute("msg","Hello!SpringMVCAnnotation!!!!!!!"); return "hello"; //交给视图处理器 } }
-
4、RestFul风格
在访问请求的时候,路径以另一种方式显示出来,不再显示ValueName,而是直接显示Value
作用:
- 不会显示变量的名字,比较安全
- 简介
- 高效
格式:
- 在传入的参数前面加入注解
@PathVariable
就会将参数映射到路径中 - 在@RequestMapping中,参数用{}包住
@Controller
public class RestFulTest {
@RequestMapping("/test1/{a}/{b}")
public String test1(@PathVariable int a, @PathVariable int b, Model model){
model.addAttribute("str","The a+b result is"+(a+b));
return "test";
}
}
- 不使用RestFul风格,原来的路径会是:https://localhost:8080/test?a=12&b=3
- 路径会显示:http://localhost:8080/test1/12/3
固定传参方式:
GET/POST/DELETE/PUT
@RequestMapping(value = "/test2/{a}/{b}",method = RequestMethod.POST)
public String test2(@PathVariable int a,@PathVariable String b,Model model){
model.addAttribute("str","The a+b result is "+(a+b));
return "test";
}
还可以直接通过改变注解来决定类型:
- @GetMapping
- @PostMapping
- @DeleteMapping
- @PutMapping
@GetMapping("/test3/{a}/{b}")
public String test3(@PathVariable int a,@PathVariable String b,Model model){
model.addAttribute("str","The a+b result is "+(a+b));
return "test";
}
5、不用视图解析器跳转
使用重定向 和 请求转发的方式来实现页面跳转
不是同视图解析器的话,路径要写全
-
通过路径直接跳转
@Controller public class ServletTest { @RequestMapping("/s1") public String hello(HttpServletRequest request, HttpServletResponse response){ HttpSession session = request.getSession(); System.out.println(session.getId()); session.setAttribute("msg","测试成功!!!"); return "/WEB-INF/jsp/hello.jsp"; } }
-
通过重定向跳转
重定向只是跳转到指定页面,不可以带参数
@RequestMapping("/s2") public String hello2(){ return "redirect:index.jsp"; }
-
通过请求转发跳转
@RequestMapping("/s3") public String hello3(Model model){ model.addAttribute("msg","gfsvsf"); return "forward:/WEB-INF/jsp/hello.jsp"; }
6、请求参数名
参数名不一致
-
使用注解
@RequestParam
-
在浏览器请求的时候,传入的参数名就得和注解中的名一模一样了
@Controller public class UserController { @RequestMapping("/u/t1") public String user(@RequestParam("username") String name, Model model){ model.addAttribute("msg","传入的数据为: "+name); return "hello"; } } http://localhost:8080/u/t1?username=test
参数为实体类
当传入的参数名与实体类中属性名不一致的时候,会得到空值
@RequestMapping("/u/t2")
public String user1(User user,Model model){
System.out.println(user);
return "hello";
}
http://localhost:8080/u/t2?name=mkie&id=12&password=vsfvdb
7、乱码问题
-
Get方式获取数据是通过tomcat解码,Tomcat解码方式为utf-8,可以对中文解码
-
Post方式获取数据是通过request解码的,而request的解码方式为iso-8859-1,不可以对中文解码
-
所以,当请求方式为Post的时候,有可能会出现乱码
自己写Filter
可以添加一个过滤器,添加语句:request.setCharacterEncoding("utf-8");
注意:!!!一定要写doFilter语句
public class EncodingFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
}
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
servletRequest.setCharacterEncoding("utf-8");
servletResponse.setCharacterEncoding("utf-8");
filterChain.doFilter(servletRequest,servletResponse);
}
public void destroy() {
}
}
添加至web.xml
-
/*表示对所有文件有效
<filter> <filter-name>enfilter</filter-name> <filter-class>com.wjh.filter.EncodingFilter</filter-class> </filter> <filter-mapping> <filter-name>enfilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
SpringMVC自带过滤器
<filter>
<filter-name>encoding</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>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
8、Json
jackson乱码解决
-
为防止Jackson转换后,数据出现乱码,在springmvc-servlet.xml中配置
mvc:annotation-driven
<mvc:annotation-driven> <mvc:message-converters register-defaults="true"> <bean class="org.springframework.http.converter.StringHttpMessageConverter"> <constructor-arg value="UTF-8"/> </bean> <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> <property name="objectMapper"> <bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean"> <property name="failOnEmptyBeans" value="false"/> </bean> </property> </bean> </mvc:message-converters> </mvc:annotation-driven>
Jackson过程
-
导入jackson jar包
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.13.4</version> </dependency>
-
配置web.xml
-
配置springmvc-servlet.xml
-
写实体类User
-
写Controller类
-
需要添加一个注解
@ResponseBody
令这个方法不走视图解析器,最后直接返回数据到浏览器 -
在类上添加注解
@RestController
可以是类下所有的方法不走视图解析器,直接返回字符串@Controller public class UserController { @ResponseBody @RequestMapping("/u1") public String u1() throws JsonProcessingException { //创建Jackson对象 ObjectMapper mapper = new ObjectMapper(); User user = new User(1,"Mike","132456"); //用Jackson将user转为String类型 String str = mapper.writeValueAsString(user); return str; } }
-
-
结果
- Jackson的格式就是:{“变量名”:“值”,***}
{"id":1,"name":"Mike","password":"132456"}
Jackson返回List
与上面一致
@ResponseBody
@RequestMapping("/u2")
public String u2() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
List<User> list = new ArrayList<User>();
User user = new User(1,"Mike1","132456");
User user1 = new User(2,"Mike2","111111");
User user2 = new User(3,"Mike3","45654345");
User user3 = new User(4,"Mike4","fdgdfgh");
list.add(user);
list.add(user1);
list.add(user2);
list.add(user3);
String str = mapper.writeValueAsString(list);
return str;
}
[{"id":1,"name":"Mike1","password":"132456"},
{"id":2,"name":"Mike2","password":"111111"},
{"id":3,"name":"Mike3","password":"45654345"},
{"id":4,"name":"Mike4","password":"fdgdfgh"}]
处理时间
Jackson默认格式为时间戳
@ResponseBody
@RequestMapping("/u3")
public String u3() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-DD HH:mm:ss");
String str = mapper.writeValueAsString(sdf.format(date));
return str;
}
工具类处理返回格式
public class JsonUtil {
public static String getJson(Object o, String s){
String str = null;
ObjectMapper mapper = new ObjectMapper();
SimpleDateFormat sdf = new SimpleDateFormat(s);
try {
str = mapper.writeValueAsString(sdf.format(o));
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return str;
}
public static String getJson(Object o){
return getJson(o,"yyyy-MM-DD HH:mm:ss");
}
}
Fastjson
9、Ajax
Ajax是一种无需重新加载整个网页的情况下,能够更新部分网页的技术。
-
Ajax格式:
$.ajax({ url:path, data:{"属性":"属性值"},//是页面传来的id success:function(reg){ 操作; }, error:function(){ 操作; } })
-
将jQuery文件导入到WEB-INF/static/js包内
-
在jsp文件中引入jQuery
<script src="${pageContext.request.contextPath}/static/js/jquery-3.6.1.js"></script>
-
写Controller.java
@RequestMapping("/a1") public void testAjax(String name, HttpServletResponse response) throws IOException { System.out.println("testName="+name); if ("Mike".equals(name)){ response.getWriter().println("yes"); }else{ response.getWriter().println("no!"); } }
-
继续写jsp中的script,实现失去焦点出现反应(就是点击了input,输入一个字符串,再点击别的地方,就会对数据进行处理,得到结果
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>$Title$</title> <script src="${pageContext.request.contextPath}/static/js/jquery-3.6.1.js"></script> <script> function a() { $.post({ url:"${pageContext.request.contextPath}/a1", //指定要传入的地址 data:{"name":$("#username").val()}, //这个data是要传到Controller的a1中的 success:function (data) { //得到data,后端的反应 alert(data); } }) } </script> </head> <body> <input type="text" id="username" οnblur="a()"> //调用function a() </body> </html>
实现登录验证
-
login.jsp
- 用户名密码输入正确,离开输入框后,直接返回结果
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous"> <script src="${pageContext.request.contextPath}/static/js/jquery-3.6.1.js"></script> <script> function a(){ $.post({ url:"${pageContext.request.contextPath}/a3", data:{"name":$("#name").val()}, success:function (data) { if (data.toString()==='ok'){ $("#userInfo").css("color","green"); }else { $("#userInfo").css("color","red"); } $("#userInfo").html(data); } }) } function b(){ $.post({ url:"${pageContext.request.contextPath}/a3", data:{"pwd":$("#pwd").val()}, success:function (data) { if (data.toString()==='ok'){ $("#pwdInfo").css("color","green"); }else { $("#pwdInfo").css("color","red"); } $("#pwdInfo").html(data); } }) } </script> </head> <body> <div class="container" style="width: 500px" > <div class="col-md-12 column" style="height: 100px"> </div> <div style="width:auto"> <form class="form-horizontal"> <div class="form-group" > <label class="col-sm-2 control-label">Name</label> <div class="col-sm-10"> <input type="text" class="form-control" id="name" placeholder="name" οnblur="a()"> <span id="userInfo"></span> </div> </div> <div class="form-group"> <label class="col-sm-2 control-label">Password</label> <div class="col-sm-10"> <input type="password" class="form-control" id="pwd" placeholder="Password" οnblur="b()"> <span id="pwdInfo"></span> </div> </div> <div class="form-group"> <div class="col-sm-offset-2 col-sm-10"> <button type="submit" class="btn btn-default">Sign in</button> </div> </div> </form> </div> </div> </body> </html>
-
Controller.java
@RequestMapping("/a3") public String test3(String name,String pwd){ String msg = ""; if (null!=name){ if ("admin".equals(name)){ msg = "ok"; }else { msg = "name is error"; } } if (null!=pwd){ if ("123456".equals(pwd)){ msg = "ok"; }else { msg = "password is error"; } } return msg; }
将登陆页面设为欢迎页面:
<welcome-file-list>
<welcome-file>/WEB-INF/jsp/login.jsp</welcome-file>
</welcome-file-list>
10、拦截器
-
Controller.java
session.setAttribute("loginInfo",user.getUserName());
-
Interceptor.java
public class LoginInterceptor implements HandlerInterceptor { public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HttpSession session = request.getSession(); if (request.getRequestURI().contains("Login")){ return true; } if (session.getAttribute("loginInfo")!=null){ return true; } request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request,response); return false; } }
-
配置springmvc.xml
<mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**"/> <bean class="com.wjh.config.LoginInterceptor"/> </mvc:interceptor> </mvc:interceptors>