狂神说
MVC:Model、View、Controller;模型、视图、控制器,是一种软件设计规范;
将业务逻辑、数据、前端显示分离的方法来组织代码;
MVC主要作用是降低视图与业务逻辑的双向耦合;
MVC是一种架构模式,并不是设计模式。
Model模型:
View视图:
Controller控制器:
最典型的MVC就是JSP + Servlet + JavaBean模式。
创建父工程,导入依赖
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
<scope>testscope>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>5.3.10version>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>servlet-apiartifactId>
<version>2.5version>
dependency>
<dependency>
<groupId>javax.servlet.jspgroupId>
<artifactId>jsp-apiartifactId>
<version>2.2version>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>jstlartifactId>
<version>1.2version>
dependency>
创建子工程, 添加web app支持
编写一个Servlet类HelloServlet.java
,用来处理用户的请求
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.获取前端参数
String method = req.getParameter("method");
if(method.equals("add")) {
req.getSession().setAttribute("msg","执行了add方法");
}
if(method.equals("delete")) {
req.getSession().setAttribute("msg", "执行了delete方法");
}
//2.调用业务层
//3.视图转发或重定向
req.getRequestDispatcher("/WEB-INF/jsp/hello.jsp").forward(req,resp);
}
@Override
protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
编写jsp跳转页面hello.jsp
, 在WEB-INF目录下
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
HelloServlet
${msg}
web.xml
中配置servlet
<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>HelloServletservlet-name>
<servlet-class>com.ano.servlet.HelloServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>HelloServletservlet-name>
<url-pattern>/hellourl-pattern>
servlet-mapping>
web-app>
配置tomcat 启动并测试
http://localhost:8080/hello?method=delete
http://localhost:8080/hello?method=add
Spring MVC是Spring Framework的一部分,是基于Java实现MVC的轻量级Web框架。
查看官方文档:22. Web MVC framework (spring.io)
特点:
Spring的web框架围绕DispatcherServlet [ 调度Servlet ] 设计。DispatcherServlet的作用是将请求分发到不同的处理器。从Spring 2.5开始,使用Java 5或者以上版本的用户可以采用基于注解Controller进行开发,十分简洁;
Spring MVC框架像许多其他MVC框架一样, 以请求为驱动 , 围绕一个中心Servlet分派请求及提供其他功能,DispatcherServlet是一个实际的Servlet (它继承自HttpServlet 基类)。
SpringMVC执行原理如图所示:其中实线表示SpringMVC框架提供的技术,不需要开发者实现,虚线表示需要开发者实现的部分。
简单分析以下以上执行原理流程
新建module springmvc-02-hellomvc,添加web框架支持;
确定导入了相关依赖;
配置web.xml
,注册Dispatcher;
<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>springmvcservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:springmvc-servlet.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>springmvcservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
web-app>
编写spring MVC配置文件springmvc-servlet.xml
<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>
编写操作业务Controller:HelloController.java
,要么实现Controller接口,要么增加注解,需要返回一个ModelAndView,装数据,封视图;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class HelloController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
//创建ModelAndView 模型和视图
ModelAndView mv = new ModelAndView();
//封装对象,放在ModelAndView中
mv.addObject("msg","HelloSpringMVC");
//封装要跳转的视图,放在ModelAndView中
mv.setViewName("hello");
return mv;
}
}
将HelloController类注册在SpringIOC容器中,在springmvc-servlet.xml
中注册bean
<bean id="/hello" class="com.ano.controller.HelloController"/>
编写要跳转的页面,/WEB-INF/jsp/hello.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
helloMvc
${msg}
配置Tomcat,启动测试!
可能存在的问题:报404,可能需要在IDEA的发布项目中添加lib依赖,具体操作如下图所示:
新建一个Moudle,并添加web支持;
由于可能存在Maven资源过滤的问题,pom.xml中完善以下配置:
<build>
<resources>
<resource>
<directory>src/main/javadirectory>
<includes>
<include>**/*.propertiesinclude>
<include>**/*.xmlinclude>
includes>
<filtering>falsefiltering>
resource>
<resource>
<directory>src/main/resourcesdirectory>
<includes>
<include>**/*.propertiesinclude>
<include>**/*.xmlinclude>
includes>
<filtering>falsefiltering>
resource>
resources>
build>
在pom.xml中引入相关依赖,在父依赖中已经引入了;
配置web.xml;
<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>SpringMVCservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:springmvc-servlet.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>SpringMVCservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
web-app>
添加Spring MVC配置文件resources/springmvc-servlet.xml
<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.ano.controller" />
<mvc:default-servlet-handler />
<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 HelloController.java
package com.ano.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/HelloController")
public class HelloController {
/**
* 在类上注册了@RequestMapping方法就会自动下移,实际地址:项目名称/HelloController/hello
* @param model
* @return
*/
@RequestMapping("/hello")
public String sayHello(Model model) {
// 向Model中添加属性msg和值,在JSP页面取出并渲染
model.addAttribute("msg","HelloSpringMVCAnnotation");
// WEB_INF/jsp/hello.jsp
return "hello";
}
}
说明:
@Controller 是为了让Spring IOC容器初始化的时候自动扫描到;
@RequestMapping 是为了映射请求路径,这里因为类和方法上都有映射,所以访问时的请求路径应该是/HelloController/hello;
方法中声明的Model类型的参数是为了把Action中的数据带到视图中;
方法返回的结果是视图的名称hello,加上配置文件后的前后缀就变成WEB_INF/jsp/hello.jsp。
创建视图层 WEB_INF/jsp/hello.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
helloMvcAnnotation
${msg}
小结
使用SpringMVC必须要配置的三大件:处理器映射器、处理器适配器、视图解析器;
通常,我们只需要手动配置视图解析器,而处理器映射器和处理器适配器只需要开启注解驱动即可。
Controller接口在
org.springframework.web.servlet.mvc
包下,该接口只有一个方法:处理请求并返回一个模型与视图对象ModelAndView
@FunctionalInterface
public interface Controller {
@Nullable
ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception;
}
测试:
新建一个Moudle,和之前一样,添加web配置;
确定导入相关依赖,并刷新;
配置web.xml
;
<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>springmvcservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:springmvc-servlet.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>springmvcservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
web-app>
添加Spring MVC配置文件resources/springmvc-servlet.xml
<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.view.InternalResourceViewResolver"
id="internalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
bean>
beans>
编写一个Controller类,ControllerTest1.java
;
public class ControllerTest1 implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
ModelAndView mv = new ModelAndView();
mv.addObject("msg","Hello ControllerTestOne");
mv.setViewName("test");
return mv;
}
}
在配置文件resources/springmvc-servlet.xml
中注册请求的bean;
<bean name="/t1" class="com.ano.controller.ControllerTest1">bean>
编写前端页面WEB-INF/jsp/test.jsp
;
<%--
Created by IntelliJ IDEA.
User: wangjiao
Date: 2022/9/13
Time: 20:22
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
${msg}
实现Controller接口定义控制器是较老的方法;
缺点:一个控制器中只能有一个方法,如果多个方法则需要定义多个控制器,比较麻烦。
@Controller注解类型用于声明Spring类的实例是一个控制器;
Spring可以使用扫描机制来找到应用程序中基于注解的控制类;
为了保证Spring能找到相应控制器,需要在配置文件中声明组件扫描,即在springmvc-servlet.xml
中声明组件扫描:
<context:component-scan base-package="com.ano.controller">context:component-scan>
增加一个控制器类,使用注解实现,ControllerTest2.java
@Controller
public class ControllerTest2 {
@RequestMapping("/t2")
public String index(Model model) {
model.addAttribute("msg","ControllerTest2");
return "test";
}
}
运行tomcat测试OK!
可以发现,两个请求都可以指向同一个视图,但是页面结果的结果是不一样的,可以看出视图是被复用的,而控制器与视图之间是弱偶合关系;
注解方式是平时使用的最多的方式。
只注解在方法上,
@Controller
public class ControllerTest3 {
@RequestMapping("/t3")
public String test3(Model model) {
model.addAttribute("msg","ControllerTest3");
return "test";
}
}
访问路径为:ip:port/项目名/t3 该测试示例的访问路径即 http://localhost:8080/t3
同时注解在类和方法上
@Controller
@RequestMapping("/admin")
public class ControllerTest3 {
@RequestMapping("/t3")
public String test3(Model model) {
model.addAttribute("msg","ControllerTest3");
return "test";
}
}
访问路径为:ip:port/项目名/admin/t3 该测试示例的访问路径即http://localhost:8080/admin/t3
Restful是一个资源定位及资源操作的风格。不是标准也不是协议,只是一种风格。基于这个风格设计的软件可以更简洁、更有层次、更易于实现缓存等机制。
功能:互联网所有的事物都可以被抽象为资源,一般使用POST、DELETE、PUT、GET等不同方法对资源进行添加、删除、修改、查询操作。
传统方式操作资源:通过不同参数来实现不同的操作效果。方法比较单一,如下所示:
http://127.0.0.1/item/queryUser.action?id=1 查询,GET
http://127.0.0.1/item/saveUser.action 新增,POST
http://127.0.0.1/item/updateUser.action 更新,POST
http://127.0.0.1/item/deleteUser.action?id=1 删除,GET或POST
使用RestFul风格操作资源,可以通过不同的请求方式来实现不同的效果,请求地址可能相同,但功能可以不同,如下所示:
http://127.0.0.1/item/1 查询,GET
http://127.0.0.1/item 新增,POST
http://127.0.0.1/item 更新,PUT
http://127.0.0.1/item/1 删除,DELETE
测试示例
@Controller
public class RestFulController {
/**
* 原生的URL:http://localhost:8080/add?a=1&b=2
*/
@RequestMapping("/add")
public String addNumTest1(int a, int b, Model model) {
model.addAttribute("msg",a+b);
return "test";
}
/**
* RestFul方式1:请求方式 method = GET
* @GetMapping() = RequestMapping("/add/{a}/{b}",method=requestMethod.GET)
* http://localhost:8080/add/2/3
*/
@GetMapping("/add/{a}/{b}")
public String addNumTest2(@PathVariable int a, @PathVariable int b, Model model) {
model.addAttribute("msg",a+b);
return "test";
}
/**
* RestFul方式2:请求方式 method = POST
* 复用了相同的URL
* http://localhost:8080/add/2/3
*/
@PostMapping("/add/{a}/{b}")
public String addNumTest3(@PathVariable int a, @PathVariable int b, Model model) {
model.addAttribute("msg",a+b);
return "test";
}
}
通过设置ModelAndView对象,并根据view的名称和视图解析器跳转到指定的页面;
页面:{视图解析器前缀} + viewName +{视图解析器后缀}
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
id="internalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
bean>
Controller类通过实现Controller接口的方式实现
public class ControllerTest1 implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
ModelAndView mv = new ModelAndView();
mv.addObject("msg","Hello ControllerTestOne");
mv.setViewName("test");
return mv;
}
}
通过设置ServletAPI的方式,不需要视图解析器。
示例:
@Controller
public class ResultServletApi {
/**
* 输出
*/
@RequestMapping("/result/t1")
public void test1(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.getWriter().print("Hello, SpringMVC result by ServletAPI");
}
/**
* 重定向
*/
@RequestMapping("/result/t2")
public void test2(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.sendRedirect("/index.jsp");
}
/**
* 转发
*/
@RequestMapping("/result/t3")
public void test3(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
request.setAttribute("msg","result/t3");
request.getRequestDispatcher("/WEB-INF/jsp/test.jsp").forward(request,response);
}
}
通过HttpServletResponse进行输出
通过HttpServletResponse实现重定向
通过HttpServletRequest实现转发
无需视图解析器的情况
@Controller
public class ResultSpringMvc {
/**
* 转发
*/
@RequestMapping("/resM/t1")
public String test1(Model model) {
model.addAttribute("msg","/resM/t1");
return "/WEB-INF/jsp/test.jsp";
}
/**
* 转发
*/
@RequestMapping("/resM/t2")
public String test2(Model model) {
model.addAttribute("msg","/resM/t2");
return "forward:/WEB-INF/jsp/test.jsp";
}
/**
* 重定向
*/
@RequestMapping("/resM/t3")
public String test2() {
return "redirect:/index.jsp";
}
}
有视图解析器的情况
@Controller
public class ResultSpringMvc2 {
/**
* 转发
*/
@RequestMapping("/resM2/t1")
public String test1(Model model) {
model.addAttribute("msg","resM2/t1");
return "test";
}
/**
* 重定向
*/
@RequestMapping("/resM2/t2")
public String test2() {
return "redirect:/index.jsp";
}
}
测试程序
@Controller
public class DataHandle {
/**
* 提交的域名称和处理方法的参数名一致
* http://localhost:8080/test?name=ano
*/
@RequestMapping("/test")
public String test(String name, Model model){
model.addAttribute("msg",name);
return "test";
}
/**
* 提交的域名称和处理方法的参数名不一致
* http://localhost:8080/test2?username=ano2
*/
@RequestMapping("/test2")
public String test2(@RequestParam("username") String name, Model model){
model.addAttribute("msg",name);
return "test";
}
/**
* 提交的参数是一个对象时,前端传的参数必须和对象名称一致,否则会null
* http://localhost:8080/user?name=ano&id=1001&age=18
* @param user
* @param model
* @return
*/
@RequestMapping("/user")
public String userInfo(User user, Model model) {
System.out.println(user);
model.addAttribute("msg",user.toString());
return "test";
}
}
实体类User
package com.ano.pojo;
/**
* @author wangjiao
* @version 1.0
* @date 2022/9/21 17:45
*/
public class User {
private int id;
private String name;
private int age;
public User() {
}
public User(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
第一种方式:ModelAndView
第二种方式:Model
第三种方式:ModelMap
简单对比:
ModelAndView 可以在储存数据的同时,可以进行设置返回的逻辑视图,进行控制展示层的跳转;
Model 只有寥寥几个方法只适合用于储存数据,简化了对于Model对象的操作和理解;
ModelMap 继承了 LinkedMap ,除了实现了自身的一些方法,同样的继承 LinkedMap 的方法和特性。
一个简单的测试程序
在首页编写一个表单index.jsp
编写响应的Controller类及处理方法
@RequestMapping("/encoding/test")
public String test(String name, Model model) {
model.addAttribute("msg",name);
return "test";
}
localhost:8080进入首页表单输入中文测试,发现会乱码
一般通过配置过滤器解决乱码问题。
EncodingFilter.java
;public class EncodingFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
servletRequest.setCharacterEncoding("utf-8");
servletResponse.setCharacterEncoding("utf-8");
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
}
}
<filter>
<filter-name>encodingfilter-name>
<filter-class>com.ano.filter.EncodingFilterfilter-class>
filter>
<filter-mapping>
<filter-name>encodingfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
web.xml
即可
<filter>
<filter-name>encodingfilter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
<init-param>
<param-name>encodingparam-name>
<param-value>utf-8param-value>
init-param>
filter>
<filter-mapping>
<filter-name>encodingfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
一般情况下,Spring框架默认的这个过滤器就已经能够很好的解决乱码问题,但是有一些极端情况,Spring框架提供的过滤器对GET请求的支持不友好,处理方法如下:
<Connector URIEncoding="utf-8" port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
package com.ano.filter;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Map;
/**
* 通用乱码过滤器:解决get和post请求全部乱码的过滤器
*/
public class GenericEncodingFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
// 处理response的字符编码
HttpServletResponse myResponse=(HttpServletResponse) response;
myResponse.setContentType("text/html;charset=UTF-8");
// 转型为与协议相关对象
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
// 对request包装增强
HttpServletRequest myrequest = new MyRequest(httpServletRequest);
filterChain.doFilter(myrequest, response);
}
@Override
public void destroy() {
}
}
/**
* 自定义request对象,HttpServletRequest的包装类
*/
class MyRequest extends HttpServletRequestWrapper {
private HttpServletRequest request;
/**
* 是否编码的标记
*/
private boolean hasEncode;
/**
* 定义一个可以传入HttpServletRequest对象的构造函数,以便对其进行装饰
* @param request
*/
public MyRequest(HttpServletRequest request) {
// super必须写
super(request);
this.request = request;
}
/**
* 对需要增强方法 进行覆盖
* @return
*/
@Override
public Map getParameterMap() {
// 先获得请求方式
String method = request.getMethod();
if (method.equalsIgnoreCase("post")) {
// post请求
try {
// 处理post乱码
request.setCharacterEncoding("utf-8");
return request.getParameterMap();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
} else if (method.equalsIgnoreCase("get")) {
// get请求
Map<String, String[]> parameterMap = request.getParameterMap();
// 确保get手动编码逻辑只运行一次
if (!hasEncode) {
for (String parameterName : parameterMap.keySet()) {
String[] values = parameterMap.get(parameterName);
if (values != null) {
for (int i = 0; i < values.length; i++) {
try {
// 处理get乱码
values[i] = new String(values[i]
.getBytes("ISO-8859-1"), "utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
}
hasEncode = true;
}
return parameterMap;
}
return super.getParameterMap();
}
/**
* 取一个值
* @param name
* @return
*/
@Override
public String getParameter(String name) {
Map<String, String[]> parameterMap = getParameterMap();
String[] values = parameterMap.get(name);
if (values == null) {
return null;
}
// 取回参数的第一个值
return values[0];
}
/**
* 取所有值
* @param name
* @return
*/
@Override
public String[] getParameterValues(String name) {
Map<String, String[]> parameterMap = getParameterMap();
String[] values = parameterMap.get(name);
return values;
}
}
JSON, JavaScript Object Notation, JS对象标记。是一种轻量级的数据交换格式;
JSON采用完全独立于编程语言的文本格式来存储和表示数据;
简洁和清晰的层次结构使得JSON成为理想的数据交换语言;
易于阅读和编写,同时也易于机器解析和生成,有效提升网络传输效率;
在JavaScript语言中,一切都是对象。因此,任何JavaScript支持的类型都可以通过JSON来表示,例如字符串、数字、数组、对象等,语法格式如下:
JSON键值对是用来保存JavaScript对象的一种方式,写法类似,键名在前面并用双引号""包裹,使用冒号:分隔,紧接着写值;
JSON是JavaScript对象的字符串表示法,它使用文本表示一个JS对象的信息,本质就是一个字符串;
// 这是一个对象
var obj = {"name":"ano","id":1001,"age":19};
// 这是一个JSON字符串
var json = '{"name":"ano","id":1001,"age":19}';
JSON和JavaScript对象互相转换
JSON字符串转换为JavaScript对象,使用JSON.parse()
方法;
var obj = JSON.parse('{"name":"ano","id":1001,"age":19}');
JavaScript对象转换为JSON字符串,使用JSON.stringify()
方法。
var json = JSON.stringify({"name":"ano","id":1001,"age":19});
代码测试,新建一个module并添加web框架支持,在web目录下新建一个html文件json-01.html
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
<script type="text/javascript">
let user = {
name:"杨和苏KeyNG",
id:1001,
age:19
};
console.log(user);
console.log("===================");
let userJson = JSON.stringify(user);
console.log(userJson);
console.log("===================");
let user2 = JSON.parse(userJson);
console.log(user2);
console.log("===================");
console.log(user2.name, user2.id, user2.age)
script>
head>
<body>
body>
html>
使用浏览器打开,查看Console:
JSON解析工具:Jackson、Fastjson
一个简单的测试,包括json乱码的处理
使用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.3</version>
</dependency>
配置SpringMVC需要的配置文件,这里只展示代码,不详细说步骤了;
web.xml
<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>SpringMVCservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:springmvc-servlet.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>SpringMVCservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
<filter>
<filter-name>encodingfilter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
<init-param>
<param-name>encodingparam-name>
<param-value>utf-8param-value>
init-param>
filter>
<filter-mapping>
<filter-name>encodingfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
web-app>
resources/springmvc-servlet.xml
<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"
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">
<context:component-scan base-package="com.ano.controller">context:component-scan>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
id="internalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
bean>
beans>
在WEB-INF下新建文件夹jsp。
编写一个实体类User.java
(添加lombok依赖)
package com.ano.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private String name;
private int id;
private int age;
}
编写一个Controller类UserController.java
package com.ano.controller;
import com.ano.pojo.User;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class UserController {
@RequestMapping("/json/t1")
@ResponseBody
public String jacksonTest() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
User user = new User("杨和苏KeyNG",1001,26);
String userStr = mapper.writeValueAsString(user);
return userStr;
}
}
发现这个乱码问题,简单处理一下:
// 通过@RequestMaping的produces属性设置响应体返回的类型和编码
@RequestMapping(value = "/json/t1", produces = "application/json;charset=utf-8")
重新测试OK
乱码问题统一解决方式
用上述方式解决虽然简单,但是项目中的每一个请求都要添加,如果太多请求,这种方式很麻烦。因此可以通过Spring配置统一处理这种乱码问题。
在springmvc-servlet.xml
添加StringHttpMessageConverter转换配置:
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg value="UTF-8">constructor-arg>
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">property>
bean>
property>
bean>
mvc:message-converters>
mvc:annotation-driven>
在Controller类上用**@RestController**r注解即可。
@RestController
public class UserController {
@RequestMapping(value = "/json/t1")
public String jacksonTest() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
User user = new User("杨和苏KeyNG",1001,26);
String userStr = mapper.writeValueAsString(user);
return userStr;
}
}
再次运行测试,完美解决Json乱码问题。
测试集合的输出
增加一个新的请求方法在UserController.java
:
@RequestMapping("/json/t2")
public String jacksonTest2() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
User user1 = new User("杨和苏KeyNG",1001,26);
User user2 = new User("车银优",1001,18);
User user3 = new User("王嘉尔",1001,27);
User user4 = new User("南柱赫",1001,26);
ArrayList<User> userList = new ArrayList<>();
userList.add(user1);
userList.add(user2);
userList.add(user3);
userList.add(user4);
String userListJson = mapper.writeValueAsString(userList);
return userListJson;
}
运行测试OK
测试时间对象的输出
增加一个新的请求方法
@RequestMapping("/json/t3")
public String jacksonTest3() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
Date date = new Date();
String dateJson = mapper.writeValueAsString(date);
return dateJson;
}
运行测试,这里Jackson默认把Date对象转换为timestamps时间戳形式:
不使用上面时间戳的形式,自定义时间格式:
@RequestMapping("/json/t4")
public String jacksonTest4() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
// 取消使用时间戳
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,false);
// 自定义时间格式
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// 指定日期格式
mapper.setDateFormat(dateFormat);
Date date = new Date();
String dateJson = mapper.writeValueAsString(date);
return dateJson;
}
运行结果:
如果经常使用,可以抽取为工具类:
package com.ano.utils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import java.text.SimpleDateFormat;
import java.util.Date;
public class JsonUtils {
public static String getJson(Object object) {
return getJson(object,"yyyy-MM-dd HH:mm:ss");
}
public static String getJson(Object object, String dataFormat) {
ObjectMapper mapper = new ObjectMapper();
// 取消使用时间戳
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,false);
// 自定义时间格式
SimpleDateFormat dateFormat = new SimpleDateFormat(dataFormat);
// 指定日期格式
mapper.setDateFormat(dateFormat);
try {
return mapper.writeValueAsString(object);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
}
使用该工具类,代码会更简洁:
@RequestMapping("/json/t5")
public String jacksonTest5() throws JsonProcessingException {
Date date = new Date();
return JsonUtils.getJson(date);
}
简单测试一下
导入Fastjson包
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.12</version>
</dependency>
简单测试一下四种转换方法的使用:
public static void main(String[] args) {
User user1 = new User("杨和苏KeyNG",1001,26);
User user2 = new User("车银优",1001,18);
ArrayList<User> userList = new ArrayList<>();
userList.add(user1);
userList.add(user2);
System.out.println("Java对象转换为JSON字符串:");
String userListJsonStr = JSON.toJSONString(userList);
System.out.println(userListJsonStr);
String userJsonStr = JSON.toJSONString(user1);
System.out.println(userJsonStr);
System.out.println();
System.out.println("JSON字符串转换为Javas对象:");
User user = JSON.parseObject(userJsonStr, User.class);
System.out.println(user);
System.out.println();
System.out.println("Java对象转换为JSON对象:");
JSONObject userJsonObj = (JSONObject)JSON.toJSON(user2);
System.out.println(userJsonObj);
System.out.println(userJsonObj.getString("name"));
System.out.println();
System.out.println("JSON对象转换为Java对象:");
User userJavaObj = JSON.toJavaObject(userJsonObj, User.class);
System.out.println(userJavaObj);
}
输出结果:
Java对象转换为JSON字符串:
[{"age":26,"id":1001,"name":"杨和苏KeyNG"},{"age":18,"id":1001,"name":"车银优"},{"age":27,"id":1001,"name":"王嘉尔"},{"age":26,"id":1001,"name":"南柱赫"}]
{"age":26,"id":1001,"name":"杨和苏KeyNG"}
JSON字符串转换为Javas对象:
User(name=杨和苏KeyNG, id=1001, age=26)
Java对象转换为JSON对象:
{"name":"车银优","id":1001,"age":18}
车银优
JSON对象转换为Java对象:
User(name=车银优, id=1001, age=18)
在Controller类中增加一个新的请求方法:
@RequestMapping("/json/t6")
public String fastjsonTest() {
User user1 = new User("杨和苏KeyNG",1001,26);
User user2 = new User("车银优",1002,18);
User user3 = new User("王嘉尔",1003,27);
User user4 = new User("南柱赫",1004,26);
List<User> userList = new ArrayList<User>();
userList.add(user1);
userList.add(user2);
userList.add(user3);
userList.add(user4);
String userListJsonStr = JSON.toJSONString(userList);
return userListJsonStr;
}
配置Tomcat运行测试:
创建数据库表
CREATE DATABASE `ssmbuild`;
USE `ssmbuild`;
DROP TABLE IF EXISTS `books`;
CREATE TABLE `books` (
`bookID` INT(10) NOT NULL AUTO_INCREMENT COMMENT '书id',
`bookName` VARCHAR(100) NOT NULL COMMENT '书名',
`bookCounts` INT(11) NOT NULL COMMENT '数量',
`detail` VARCHAR(200) NOT NULL COMMENT '描述',
KEY `bookID` (`bookID`)
) ENGINE=INNODB DEFAULT CHARSET=utf8
INSERT INTO `books`(`bookID`,`bookName`,`bookCounts`,`detail`)VALUES
(1,'Java',1,'从入门到放弃'),
(2,'MySQL',10,'从删库到跑路'),
(3,'Linux',5,'从进门到进牢');
搭建Maven项目环境
创建一个Maven工程,并添加Web支持;
在pom.xml中导入相关依赖;
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
<scope>testscope>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.47version>
dependency>
<dependency>
<groupId>com.mchangegroupId>
<artifactId>c3p0artifactId>
<version>0.9.5.2version>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>servlet-apiartifactId>
<version>2.5version>
dependency>
<dependency>
<groupId>javax.servlet.jspgroupId>
<artifactId>jsp-apiartifactId>
<version>2.2version>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>jstlartifactId>
<version>1.2version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.5.9version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatis-springartifactId>
<version>2.0.6version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>5.3.10version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
<version>5.3.10version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.18.24version>
<scope>providedscope>
dependency>
maven资源过滤配置,在pom.xml中设置:
<build>
<resources>
<resource>
<directory>src/main/javadirectory>
<includes>
<include>**/*.propertiesinclude>
<include>**/*.xmlinclude>
includes>
<filtering>falsefiltering>
resource>
<resource>
<directory>src/main/resourcesdirectory>
<includes>
<include>**/*.propertiesinclude>
<include>**/*.xmlinclude>
includes>
<filtering>falsefiltering>
resource>
resources>
build>
创建基本的项目结构和配置框架;
com.ano.controller
com.ano.dao
com.ano.pojo
com.ano.service
resources/mybatis-config.xml
DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
configuration>
resources/applicationContext.xml
<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">
beans>
基于以上写一个简单的测试
数据库配置文件resources/database.properties
jdbc.driver= com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssmbuild?useSSL=true&useUnicode=true&characterEncoding=utf8
jdbc.username=root
jdbc.password=123456
IDEA关联数据库表
Mybatis核心配置文件mybatis-config.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>
<typeAliases>
<package name="com.ano.pojo"/>
</typeAliases>
</configuration>
编写数据库表对应的实体类Books.java
,(用了lombok插件)
package com.ano.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Books {
/**
* 书籍ID
*/
private int bookID;
/**
* 书籍名称
*/
private String bookName;
/**
* 书籍数量
*/
private int bookCounts;
/**
* 书籍简介
*/
private String detail;
}
编写Dao层Mapper接口BooksMapper.java
package com.ano.dao;
import com.ano.pojo.Books;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface BooksMapper {
/**
* 增加一本书
* @param book
* @return
*/
int addBook(Books book);
/**
* 根据ID删除一本书
* @param id
* @return
*/
int deleteBookById(@Param("bookID") int id);
/**
* 修改一本书
* @param book
* @return
*/
int updateBook(Books book);
/**
* 查询一本书
* @param id
* @return
*/
Books queryBookById(@Param("bookID") int id);
/**
* 查询所有书
* @return
*/
List<Books> queryAllBooks();
}
编写Mapper接口对应的Mapper.xml文件,BooksMapper.xml
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ano.dao.BooksMapper">
<insert id="addBook" parameterType="Books">
insert into ssmbuild.books(bookName, bookCounts, detail)
values (#{bookName}, #{bookCounts}, #{detail})
insert>
<delete id="deleteBookById" parameterType="int">
delete from ssmbuild.books
where bookID = #{bookID}
delete>
<update id="updateBook" parameterType="Books">
update ssmbuild.books
set bookName = #{bookName}, bookCounts = #{bookCounts}, detail = #{detail}
where bookID = #{bookID}
update>
<select id="queryBookById" parameterType="int" resultType="Books">
select * from ssmbuild.books
where bookID = #{bookID}
select>
<select id="queryAllBooks" resultType="Books">
select * from ssmbuild.books
select>
mapper>
这里!记得在Mybatis核心配置文件mybatis-config.xml
中注册mapper;
DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<typeAliases>
<package name="com.ano.pojo"/>
typeAliases>
<mappers>
<mapper class="com.ano.dao.BooksMapper">mapper>
mappers>
configuration>
编写Service层的接口及对应实现类
BooksService.java
package com.ano.service;
import com.ano.pojo.Books;
import java.util.List;
public interface BooksService {
/**
* 增加一本书
* @param book
* @return
*/
int addBook(Books book);
/**
* 根据ID删除一本书
* @param id
* @return
*/
int deleteBookById(int id);
/**
* 修改一本书
* @param book
* @return
*/
int updateBook(Books book);
/**
* 查询一本书
* @param id
* @return
*/
Books queryBookById(int id);
/**
* 查询所有书
* @return
*/
List<Books> queryAllBooks();
}
BooksServiceImpl.java
package com.ano.service;
import com.ano.dao.BooksMapper;
import com.ano.pojo.Books;
import java.util.List;
public class BooksServiceImpl implements BooksService{
/**
* service调用dao层 set接口方便Spring管理
*/
private BooksMapper booksMapper;
public void setBooksMapper(BooksMapper booksMapper) {
this.booksMapper = booksMapper;
}
@Override
public int addBook(Books book) {
return booksMapper.addBook(book);
}
@Override
public int deleteBookById(int id) {
return booksMapper.deleteBookById(id);
}
@Override
public int updateBook(Books book) {
return booksMapper.updateBook(book);
}
@Override
public Books queryBookById(int id) {
return booksMapper.queryBookById(id);
}
@Override
public List<Books> queryAllBooks() {
return booksMapper.queryAllBooks();
}
}
编写Spring整合Mybatis (dao层) 的配置文件spring-dao.xml
这里使用的数据库连接池是c3p0。特别注意第4步骤!
<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"
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">
<context:property-placeholder location="classpath:database.properties"/>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="maxPoolSize" value="30"/>
<property name="minPoolSize" value="10"/>
<property name="autoCommitOnClose" value="false"/>
<property name="checkoutTimeout" value="10000"/>
<property name="acquireRetryAttempts" value="2"/>
bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:mybatis-config.xml"/>
bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<property name="basePackage" value="com.ano.dao"/>
bean>
beans>
配置Spring整合service层,编写spring-service.xml
<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"
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">
<context:component-scan base-package="com.ano.service"/>
<bean id="booksServiceImpl" class="com.ano.service.BooksServiceImpl">
<property name="booksMapper" ref="booksMapper"/>
bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
bean>
beans>
到此,Spring层配置完成,可以看出Spring就是一个容器,很形象了!
记得项目要添加Web框架支持!
配置文件web/WEB-INF/web.xml
<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">
<absolute-ordering/>
<servlet>
<servlet-name>springmvcservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:applicationContext.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>springmvcservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
<filter>
<filter-name>encodingFilterfilter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
<init-param>
<param-name>encodingparam-name>
<param-value>utf-8param-value>
init-param>
filter>
<filter-mapping>
<filter-name>encodingFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
<session-config>
<session-timeout>15session-timeout>
session-config>
web-app>
编写配置文件resources/spring-mvc.xml
<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">
<mvc:annotation-driven/>
<mvc:default-servlet-handler/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
bean>
<context:component-scan base-package="com.ano.controller"/>
beans>
Spring配置整合文件resources/applicationContext.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">
<import resource="spring-dao.xml"/>
<import resource="spring-service.xml"/>
<import resource="spring-mvc.xml"/>
</beans>
到此,配置完成!
编写Controller层,BooksController.java
,首先写一个请求方法查询所有书籍列表
@Controller
@RequestMapping("/book")
public class BooksController {
@Autowired
@Qualifier("booksServiceImpl")
private BooksService booksService;
/**
* 查询所有书籍
* @param model
* @return
*/
@RequestMapping("/allBooks")
public String bookList(Model model) {
List<Books> bookList = booksService.queryAllBooks();
for (Books book : bookList) {
System.out.println(book.getBookID());
System.out.println(book.getBookName());
}
model.addAttribute("bookList",bookList);
return "allBooks";
}
}
编写首页index.jsp
; 注意路径!就是Controller中查询所有书籍方法的请求路径;
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
首页
点击进入书籍列表页面
书籍列表页面WEB-INF/jsp/allBooks.jsp
;
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
新增书籍
新增书籍
接下来就是根据allBooks.jsp
书籍列表页的相关路径和参数,实现新增、修改、删除数据功能,不展开写了,看整体代码:
BooksController.java
package com.ano.controller;
import com.ano.pojo.Books;
import com.ano.service.BooksService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.List;
@Controller
@RequestMapping("/book")
public class BooksController {
@Autowired
@Qualifier("booksServiceImpl")
private BooksService booksService;
/**
* 查询所有书籍
* @param model
* @return
*/
@RequestMapping("/allBooks")
public String bookList(Model model) {
List<Books> bookList = booksService.queryAllBooks();
for (Books book : bookList) {
System.out.println(book.getBookID());
System.out.println(book.getBookName());
}
model.addAttribute("bookList",bookList);
return "allBooks";
}
/**
* 新增书籍
* @return
*/
@RequestMapping("/toAddBook")
public String toAddBook() {
return "addBook";
}
@RequestMapping("/addBook")
public String addBook(Books book) {
booksService.addBook(book);
return "redirect:/book/allBooks";
}
/**
* 修改书籍
* @param id
* @param model
* @return
*/
@RequestMapping("/toUpdateBook")
public String toUpdateBook(int id,Model model) {
Books book = booksService.queryBookById(id);
model.addAttribute("book",book);
return "updateBook";
}
@RequestMapping("/updateBook")
public String updateBook(Books book) {
booksService.updateBook(book);
return "redirect:/book/allBooks";
}
/**
* 删除书籍
* @param id
* @return
*/
@RequestMapping("/del/{bookID}")
public String deleteBook(@PathVariable("bookID") int id) {
booksService.deleteBookById(id);
return "redirect:/book/allBooks";
}
}
新增书籍页面WEB-INF/jsp/addBook.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
新增书籍
新增书籍
修改书籍页面WEB-INF/jsp/updateBook.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
修改书籍信息
修改书籍信息
最后,整体看一下项目结构!
添加log4j依赖;
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
编写配置文件resources/log4j.properties
### set log levels ###
log4j.rootLogger = DEBUG , C , D , E
### console ###
log4j.appender.C = org.apache.log4j.ConsoleAppender
log4j.appender.C.Target = System.out
log4j.appender.C.layout = org.apache.log4j.PatternLayout
log4j.appender.C.layout.ConversionPattern = [ssm_study][%p] [%-d{yyyy-MM-dd HH\:mm\:ss}] %C.%M(%L) | %m%n
### log file ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = ../logs/mybatis_study.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = INFO
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = [mybatis_study][%p] [%-d{yyyy-MM-dd HH\:mm\:ss}] %C.%M(%L) | %m%n
### exception ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File = ../logs/mybatis_study_error.log
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = [mybatis_study][%p] [%-d{yyyy-MM-dd HH\:mm\:ss}] %C.%M(%L) | %m%n
###mybatis show sql###
log4j.logger.com.ibatis=debug
log4j.logger.com.ibatis.common.jdbc.SimpleDataSource=debug
log4j.logger.com.ibatis.common.jdbc.ScriptRunner=debug
log4j.logger.com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate=debug
log4j.logger.java.sql.Connection=debug
log4j.logger.java.sql.Statement=debug
log4j.logger.java.sql.PreparedStatement=debug
在Mybatis核心配置文件mybatis-config.xml
中添加settings配置日志,注意顺序!
DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="logImpl" value="LOG4J"/>
settings>
<typeAliases>
<package name="com.ano.pojo"/>
typeAliases>
<mappers>
<mapper class="com.ano.dao.BooksMapper">mapper>
mappers>
configuration>
运行测试OK
XMLHttpRequest 是 Ajax 的基础和核心。
XMLHttpRequest 用于在后台与服务器交换数据。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。
创建XMLHttpRequest对象
var xmlhttp;
if (window.XMLHttpRequest)
{
// IE7+, Firefox, Chrome, Opera, Safari 浏览器执行代码
xmlhttp=new XMLHttpRequest();
}
else
{
// IE6, IE5 浏览器执行代码
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
XMLHttpRequest 对象用于和服务器交换数据。
如需将请求发送到服务器,使用 XMLHttpRequest 对象的 open() 和 send() 方法:
方法 | 描述 |
---|---|
open(method,url,async) | 规定请求的类型、URL 以及是否异步处理请求。method:请求的类型;GET 或 POSTurl:文件在服务器上的位置async:true(异步)或 false(同步) |
send(string) | 将请求发送到服务器。string:仅用于 POST 请求 |
如需像 HTML 表单那样 POST 数据,使用setRequestHeader() 方法来添加 HTTP 头。然后在 send() 方法中规定希望发送的数据:
方法 | 描述 |
---|---|
setRequestHeader(header,value) | 向请求添加 HTTP 头。header: 规定头的名称value: 规定头的值 |
xmlhttp.open("POST","/try/ajax/demo_post2.php",true);
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded"); xmlhttp.send("fname=Henry&lname=Ford");
如需获得来自服务器的响应,请使用 XMLHttpRequest 对象的 responseText 或 responseXML 属性。
属性 | 描述 |
---|---|
responseText | 获得字符串形式的响应数据。 |
responseXML | 获得 XML 形式的响应数据。 |
onreadystatechange 事件:
当请求被发送到服务器时,我们需要执行一些基于响应的任务。每当 readyState 改变时,就会触发 onreadystatechange 事件。readyState 属性存有 XMLHttpRequest 的状态信息。
下面是 XMLHttpRequest 对象的三个重要的属性:
属性 | 描述 |
---|---|
onreadystatechange | 存储函数(或函数名),每当 readyState 属性改变时,就会调用该函数。 |
readyState | 存有 XMLHttpRequest 的状态。从 0 到 4 发生变化。0: 请求未初始化1: 服务器连接已建立2: 请求已接收3: 请求处理中4: 请求已完成,且响应已就绪 |
status | 200: “OK” 404: 未找到页面 |
在 onreadystatechange 事件中,规定当服务器响应已做好被处理的准备时所执行的任务。当 readyState 等于 4 且状态为 200 时,表示响应已就绪:
xmlhttp.onreadystatechange=function() {
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
}
}
注意: onreadystatechange 事件被触发 4 次(0 - 4), 分别是: 0-1、1-2、2-3、3-4,对应着 readyState 的每个变化。
回调函数
回调函数是一种以参数形式传递给另一个函数的函数。
如果网站上存在多个 AJAX 任务,应该为创建 XMLHttpRequest 对象编写一个标准的函数,并为每个 AJAX 任务调用该函数。
该函数调用应该包含 URL 以及发生 onreadystatechange 事件时执行的任务(每次调用可能不尽相同):
function myFunction() {
loadXMLDoc("/try/ajax/ajax_info.txt",function() {
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
}
});
}
Ajax的核心是XMLHttpRequest对象(XHR)。XHR为向服务器发送请求和解析服务器响应提供了接口。能够以异步方式从服务器获取新数据。
jQuery 提供多个与 AJAX 有关的方法。
通过 jQuery AJAX 方法,能够使用 HTTP Get 和 HTTP Post 从远程服务器上请求文本、HTML、XML 或 JSON ,同时能够把这些外部数据直接载入网页的被选元素中。
jQuery Ajax本质就是 XMLHttpRequest,对其进行了封装,方便调用!
语法:
$.ajax({name:value, name:value, ... })
参数
名称 | 值/描述 |
---|---|
url | 请求的 URL。默认是当前页面。 |
type | 请求方式,GET、POST(1.9.0之后用method) |
headers | 请求头 |
data | 规定要发送到服务器的数据。 |
contentType | 发送数据到服务器时所使用的内容类型。默认是:“application/x-www-form-urlencoded”。 |
async | 布尔值,请求是否异步处理。默认是 true。 |
timeout | 设置本地的请求超时时间(以毫秒计)。 |
beforeSend(xhr) | 发送请求前运行的函数。 |
complete(xhr,status) | 请求完成时运行的回调函数(在请求成功或失败之后均调用,即在 success 和 error 函数之后)。 |
success(result,status,xhr) | 当请求成功时运行的函数。 |
error(xhr,status,error) | 如果请求失败要运行的函数。 |
accepts | 通过请求头发送给服务器,告诉服务器当前客户端可接受的数据类型 |
dataType | 将服务器端返回的数据转换成指定类型 |
“xml” | 将服务器端返回的内容转换成xml格式 |
“text” | 将服务器端返回的内容转换成普通文本格式 |
“html” | 将服务器端返回的内容转换成普通文本格式,在插入DOM中时,如果包含JavaScript标签,则会尝试去执行。 |
“script” | 尝试将返回值当作JavaScript去执行,然后再将服务器端返回的内容转换成普通文本格式 |
“json” | 将服务器端返回的内容转换成相应的JavaScript对象 |
jsonp | 在一个 jsonp 中重写回调函数的字符串。 |
jsonpCallback | 在一个 jsonp 中规定回调函数的名称。 |
cache | 布尔值,表示浏览器是否缓存被请求页面。默认是 true。 |
context | 为所有 AJAX 相关的回调函数规定 “this” 值。 |
dataFilter(data,type) | 用于处理 XMLHttpRequest 原始响应数据的函数。 |
global | 布尔值,规定是否为请求触发全局 AJAX 事件处理程序。默认是 true。 |
ifModified | 布尔值,规定是否仅在最后一次请求以来响应发生改变时才请求成功。默认是 false。 |
password | 规定在 HTTP 访问认证请求中使用的密码。 |
processData | 布尔值,规定通过请求发送的数据是否转换为查询字符串。默认是 true。 |
scriptCharset | 规定请求的字符集。 |
traditional | 布尔值,规定是否使用参数序列化的传统样式。 |
username | 规定在 HTTP 访问认证请求中使用的用户名。 |
xhr | 用于创建 XMLHttpRequest 对象的函数。 |
简单测试一下:
编写springmvc的配置文件resources/spring-mvc.xml
;
<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.ano.controller"/>
<mvc:default-servlet-handler/>
<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>
配置web.xml
;
<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>springmvcservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:spring-mvc.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>springmvcservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
<filter>
<filter-name>encodingFilterfilter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
<init-param>
<param-name>encodingparam-name>
<param-value>utf-8param-value>
init-param>
filter>
<filter-mapping>
<filter-name>encodingFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
web-app>
编写一个Controller类AjaxControler.java
package com.ano.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Controller
public class AjaxController {
@RequestMapping("/a1")
public void ajaxTest(String name, HttpServletResponse response) throws IOException {
if("admin".equals(name)) {
response.getWriter().print(true);
} else {
response.getWriter().print(false);
}
}
}
下载jquery
在官网下载jquery,jquery-3.6.1.js
, 路径为web\statics\js\jquery-3.6.1.js
编写index.jsp
进行测试
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
$Title$
用户名:
配置tomcat运行测试,会看到鼠标离开输入框时会发出一个ajax请求
一个简单测试 SpringMVC实现
编写一个实体类User.java
, 这里使用lombok插件;
package com.ano.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private String name;
private int age;
private String gender;
}
编写AjaxController类的一个测试接口AjaxController.java
@RestController
public class AjaxController {
@RequestMapping("/a2")
public List<User> ajaxTest2() {
List<User> userList = new ArrayList<User>();
userList.add(new User("KeyNG",26,"男"));
userList.add(new User("Ano",26,"女"));
userList.add(new User("西西PERSISTING",19,"女"));
return userList;
}
}
编写前端页面,就在index.jsp
页面修改
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
姓名
年龄
性别
导入依赖jackson-databind,否则会报错
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.3</version>
</dependency>
配置Tomcat运行测试
附上spring配置文件spring-mvc.xml
<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.ano.controller"/>
<mvc:default-servlet-handler/>
<mvc:annotation-driven>
<mvc:message-converters>
<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>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
id="internalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
bean>
beans>
一个简单测试 SpringMVC实现,基于10.4章节,配置不用动
编写Controller类
@RequestMapping("/a3")
public String ajaxTest3(String name, String password) {
String msg = "";
if(name != null) {
if("admin".equals(name)) {
msg="Ok";
}else {
msg="用户名输入错误";
}
}
if(password != null) {
if("123456".equals(password)) {
msg="Ok";
}else {
msg="密码输入错误";
}
}
return msg;
}
登录前端页面login.jsp
,为了便于测试,与index.jsp同路径
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
用户名:
密码:
测试
SpringMVC的处理器拦截器(HanderInterceptor)类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理;
开发者可以自己定义一些拦截器来实现特定的功能。
**过滤器与拦截器的区别:**拦截器是AOP思想的具体应用。
过滤器
servlet规范中的一部分,任何javaweb工程都可以使用;
在url-pattern中配置了/*之后,可以对所有要访问的资源进行拦截。
拦截器
拦截器是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能使用;
拦截器只会拦截访问的控制器方法, 如果访问的是jsp/html/css/image/js是不会进行拦截的。
一个简单的测试
新建一个module,添加web支持;
编写springmvc配置文件resources/spring-mvc.xml
<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.ano.controller"/>
<mvc:default-servlet-handler/>
<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>
配置web.xml
文件
<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>springmvcservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:spring-mvc.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>springmvcservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
<filter>
<filter-name>encodingFilterfilter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
<init-param>
<param-name>encodingparam-name>
<param-value>utf-8param-value>
init-param>
filter>
<filter-mapping>
<filter-name>encodingFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
web-app>
自定义一个拦截器
package com.ano.config;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyInterceptor implements HandlerInterceptor {
/**
* return true;放行,执行下一个拦截器
* return false;拦截,不执行下一个拦截器
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("================处理前===============");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("================处理后===============");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("================清理===============");
}
}
在spring配置文件中配置拦截器resources/spring-mvc.xml
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.ano.config.MyInterceptor"/>
mvc:interceptor>
mvc:interceptors>
编写一个Controller简单测试一下
@RestController
public class TestController {
@RequestMapping("/interceptor")
public String test() {
System.out.println("TestController.java");
return "ok";
}
}
配置Tomcat运行测试OK
================处理前===============
TestController.java
================处理后===============
================清理===============
通过拦截器实现验证用户是否登录,如果登录则进入首页,否则无法进入首页。
编写前端登录页面web/WEB-INF/jsp/login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
登录页面
编写前端登录后的首页页面web/WEB-INF/jsp/main.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
首页
${user}
注销
编写一个Controller类处理请求UserController.java
@Controller
@RequestMapping("/user")
public class UserController {
/**
* 进入首页
*/
@RequestMapping("/main")
public String main() {
return "main";
}
/**
* 跳转到登录页面
*/
@RequestMapping("/goLogin")
public String goLogin() {
return "login";
}
/**
* 登录
*/
@RequestMapping("/login")
public String login(HttpSession session, String username, String password, Model model) {
System.out.println("from前端=="+username);
// 把用户的信息存在session中
session.setAttribute("user", username);
model.addAttribute("user",username);
return "main";
}
/**
* 退出登录
*/
@RequestMapping("/logout")
public String logout(HttpSession session) {
// session.invalidate();
session.removeAttribute("user");
return "login";
}
}
在index.jsp
页面测试跳转
<%--
Created by IntelliJ IDEA.
User: wangjiao
Date: 2022/10/9
Time: 14:29
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
$Title$
登录
首页
编写一个拦截器LoginInterceptor.java
package com.ano.config;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 如果是登录页面则放行
if(request.getRequestURI().contains("login")) {
return true;
}
// 如果用户已登录也放行
HttpSession session = request.getSession();
if(session.getAttribute("user") != null) {
return true;
}
// 如果用户没有登录则跳转到登录页面
request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request,response);
return false;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
此时运行测试,会发现即使用户没有登录也能进入首页;
在spring配置文件中配置拦截器resources/spring-mvc.xml
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.ano.config.MyInterceptor"/>
mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/user/**"/>
<bean class="com.ano.config.LoginInterceptor"/>
mvc:interceptor>
mvc:interceptors>
再次测试登录拦截功能OK!
简单起见,使用
index.jsp
作为前端页面进行测试
一个简单的测试
新建一个module,并添加web支持;
导入以下依赖:
<dependency>
<groupId>commons-fileuploadgroupId>
<artifactId>commons-fileuploadartifactId>
<version>1.4version>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>4.0.1version>
dependency>
配置spring配置文件resources/spring-mvc.xml
,这里同时配置了文件上传的bean;
<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.ano.controller"/>
<mvc:default-servlet-handler/>
<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>
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="utf-8"/>
<property name="maxUploadSize" value="10485760"/>
<property name="maxInMemorySize" value="40960"/>
bean>
beans>
配置web.xml;这个写了很多遍了,基本上是固定写法了。这里省略了防止乱码的filter
<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>springmvcservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:spring-mvc.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>springmvcservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
web-app>
编写前端页面index.jsp
编写Controller类FileController.java
处理请求,有两种方式
package com.ano.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
@Controller
public class FileController {
/**
* 上传文件
*/
@RequestMapping("/upload")
public String uploadFile(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) throws IOException {
String uploadFileName = file.getOriginalFilename();
if("".equals(uploadFileName)) {
return "redirect:/index.jsp";
}
String path = request.getServletContext().getRealPath("/upload");
File realPath = new File(path);
if(!realPath.exists()) {
realPath.mkdirs();
}
System.out.println(realPath);
InputStream inputStream = file.getInputStream();
OutputStream outputStream = new FileOutputStream(new File(realPath, uploadFileName));
int len = 0;
byte[] buffer = new byte[1024];
while ((len = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, len);
outputStream.flush();
}
// 先开后关
outputStream.close();
inputStream.close();
return "redirect:/index.jsp";
}
/**
* 上传文件 使用CommonsMultipartFile的transferTo方法
*/
@RequestMapping("/upload2")
public String uploadFile2(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) throws IOException {
String path = request.getServletContext().getRealPath("/upload");
File realPath = new File(path);
if(!realPath.exists()) {
realPath.mkdirs();
}
System.out.println(realPath);
file.transferTo(new File(realPath + "/" + file.getOriginalFilename()));
return "redirect:/index.jsp";
}
}
配置Tomcat运行测试,两种方式测试时,改一下index.jsp中表单的action属性值即可
基于12.1上传文件的基础上,配置不懂,写一个处理文件下载的请求即可FileController.java
/**
* 下载文件
*/
@RequestMapping("/download")
public String downloadFile(HttpServletRequest request, HttpServletResponse response) throws IOException {
// 获取下载文件的地址
String path = request.getServletContext().getRealPath("/upload");
String filename = "readMe.txt";
// 1. 设置response响应头
response.reset();
response.setCharacterEncoding("UTF-8");
response.setContentType("multipart/form-data");
response.setHeader("Content-Disposition","attachment;fileName=" + URLEncoder.encode(filename,"UTF-8"));
// 2. 读取文件 输入流
File file = new File(path,filename);
InputStream inputStream = new FileInputStream(file);
// 3. 写出文件 输出流
OutputStream outputStream = response.getOutputStream();
// 4. 执行写出操作
byte[] buffer = new byte[1024];
int len = 0;
while((len = inputStream.read(buffer)) != -1) {
outputStream.write(buffer,0,len);
outputStream.flush();
}
// 5. 关闭流
outputStream.close();
inputStream.close();
return null;
}
前端页面index.jsp
写一个下载文件的链接
下载文件
测试