石一歌的SpringMVC笔记
SpringMVC
原理
图为SpringMVC的一个较完整的流程图,实线表示SpringMVC框架提供的技术,不需要开发者实现,虚线表示需要开发者实现。
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">
<!--配置DispatcherServlet:SpringMVC核心-->
<servlet>
<servlet-name>SpringMvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--关联一个SpringMvc的resource配置文件-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:SpringMVC.xml</param-value>
</init-param>
<!--启动级别-->
<load-on-startup>1</load-on-startup>
</servlet>
<!--匹配所有的请求:
/ :只匹配请求,不包含所有的.jsp
/* :匹配所有的请求,包括jsp页面
-->
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
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:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://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/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--处理器映射器HandlerMapping:查找访问的url控制器-->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<!--处理器适配器HandlerAdapter:controller将处理好的数据返回给HandlerAdapter-->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
<!--视图解析器ViewResolver:将后端处理好的数据和视图传给DispatchServlet,DS再交给ViewResolver先解析一遍,确认无误再传给前端
必须熟悉,以后还要学模版引擎Thymeleaf/Freemarker...
1 获取ModeAndView的数据
2 解析ModeAndView的视图名字
3 拼接视图名字,找到对应的视图 WEB-INF/jsp/hello.jsp
-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
<!--BeanNameUrlHandlerMapping处理器:绑定跳转的url=页面访问的网址-->
<bean id="/hello" class="com.ssl.controller.HelloController"/>
</beans>
编写控制层
public class HelloController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
//1 创建modelAndView
ModelAndView mv = new ModelAndView();
//2 调用业务层,这里没有,就不写
//3 封装对象,放在mv中添加
mv.addObject("msg", "Hello SpringMvc");
//4 封装要跳转的视图,WEB-INF/jsp/hello.jsp
mv.setViewName("hello");
return mv;
}
}
编写视图层
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>hello</title>
</head>
<body>
<%--接受传递的参数--%>
${msg}
</body>
</html>
总结
注解实现
资源过滤
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
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">
<!--1.注册servlet-->
<servlet>
<servlet-name>SpringMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--通过初始化参数指定SpringMVC配置文件的位置,进行关联-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:SpringMVC.xml</param-value>
</init-param>
<!-- 启动顺序,数字越小,启动越早 -->
<load-on-startup>1</load-on-startup>
</servlet>
<!--所有请求都会被springmvc拦截 -->
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
/ 和 /* 的区别:< url-pattern > / </ url-pattern > 不会匹配到.jsp, 只针对我们编写的请求;即:.jsp 不会进入spring的 DispatcherServlet类 。< url-pattern > /* </ url-pattern > 会匹配 *.jsp,会出现返回 jsp视图 时再次进入spring的DispatcherServlet 类,导致找不到对应的controller所以报404错。
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:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://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">
<!--自动扫描包,让指定包下的注解生效,由IOC容器统一管理-->
<context:component-scan base-package="com.ssl.controller"/>
<!--让SpringMvc不处理静态资源。让.css,.js等不进视图解析器-->
<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
public class HelloController {
/**
* @param model 模型
* @return 被视图解析器处理:访问"/WEB-INF/jsp/hello.jsp资源
* 访问的url:RequestMapping("/hello")
*/
@RequestMapping("/hello")
public String hello(Model model) {
//封装数据
model.addAttribute("msg", "Hello SpringMvc_annotation");
//被视图解析器处理:访问"/WEB-INF/jsp/hello.jsp资源
return "hello";
}
编写视图层
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>hello</title>
</head>
<body>
${msg}
</body>
</html>
@Controller
乱码过滤器
配置在web.xml
<filter>
<filter-name>encode</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>encode</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
乱码过滤增强
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 destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 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);
chain.doFilter(myRequest, response);
}
@Override
public void init(FilterConfig filterConfig){
}
}
//自定义request对象,HttpServletRequest的包装类
class MyRequest extends HttpServletRequestWrapper {
private final HttpServletRequest request;
//是否编码的标记
private boolean hasEncode;
//定义一个可以传入HttpServletRequest对象的构造函数,以便对其进行装饰
public MyRequest(HttpServletRequest request) {
super(request);// super必须写
this.request = request;
}
// 对需要增强方法 进行覆盖
@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();
if (!hasEncode) { // 确保get手动编码逻辑只运行一次
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();
}
//取一个值
@Override
public String getParameter(String name) {
Map<String, String[]> parameterMap = getParameterMap();
String[] values = parameterMap.get(name);
if (values == null) {
return null;
}
return values[0]; // 取回参数的第一个值
}
//取所有值
@Override
public String[] getParameterValues(String name) {
Map<String, String[]> parameterMap = getParameterMap();
return parameterMap.get(name);
}
}
使用注解开发,@Controller注册进Spring容器,如果返回值是String,并且有具体的页面可以跳转,那么就会被视图解析器解析
@Controller
public class ControllerDemo2 {
@RequestMapping("/demo2")
public String gcore(Model model) {
model.addAttribute("demo2", "demo2");
return "demo2";
}
}
@RequestMapping
可以在类和方法上配置url访问路径
@Controller
@RequestMapping("/controller")
public class ControllerDemo3 {
@RequestMapping("/demo3")
public String gcore(Model model) {
model.addAttribute("demo3", "demo3");
return "demo3";
}
}
转发&重定向
@Controller
@RequestMapping("/test")
public class DemoController {
//原生转发,不走视图解析器
@RequestMapping("/f1")
public void F1(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setAttribute("demo","F1");
request.getRequestDispatcher("/WEB-INF/jsp/demo.jsp").forward(request,response);
}
//SpringMVC转发,不走视图解析器
@RequestMapping("/f2")
public String F2(Model model) {
model.addAttribute("demo","F2");
return "forward:/WEB-INF/jsp/demo.jsp";
}
//视图解析器转发
@RequestMapping("/f3")
public String F3(Model model) {
model.addAttribute("demo","F3");
return "demo";
}
//SpringMVC转发,必须注释视图解析器
@RequestMapping("/f4")
public String F4(Model model) {
model.addAttribute("demo","F4");
return "/WEB-INF/jsp/demo.jsp";
}
//因为重定向是两次请求,两次响应,在服务器给定重定向后,实际上只是给了浏览器端一个下一次请求的地址,这时浏览器重新请求,如果jsp在WEB-INF下则会报404错误,因为对于WEB-INF下的jsp文件只能通过请求转发进行,而对于web下的jsp文件能正常进行访问
//所以想要进行WEB-INF下jsp之间重定向只能通过controller之间跳转一个空的请求转发进行重定向,相当于用户第二次访问的是一个controller:
//原生重定向
@RequestMapping("/r1")
public void R2(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.sendRedirect("/WEB-INF/demo2.jsp");
}
//SpringMVC重定向:测试结果是不走视图解析器
@RequestMapping("/r2")
public String R2() {
System.out.println("跳转回首页index.jsp");
return "redirect:index.jsp";
}
}
RestFul
@Controller
public class RestFulController {
/**
* 原生的url:http://localhost:8080/springmvc_04/add?a=1&b=1
*/
@RequestMapping("/add")
public String getAdd1(int a, int b, Model model) {
int result = a + b;
model.addAttribute("add", "原生的url:结果为" + result);
return "add";
}
/**
* RestFul方式一:method = get
* RequestMapping("/addRest/{a}/{b}" method=requestMethod.GET) = @GetMapping()
* http://localhost:8080/springmvc_04/addRest/1/1
*/
@GetMapping("/addRest/{a}/{b}")
public String getAdd2(@PathVariable int a, @PathVariable int b, Model model) {
int result = a + b;
model.addAttribute("add", "Rest的url:结果为" + result);
return "addRest";
}
/**
* 复用相同的url
* RestFul方式二:method=post,使用RestFul的话,请求的url和GET就一样了
*/
@PostMapping("/addRest/{a}/{b}")
public String getAdd3(@PathVariable int a, @PathVariable int b, Model model) {
int result = a + b;
model.addAttribute("add", "Rest的url:结果为" + result);
return "addRest";
}
}
使用method属性指定请求类型
用于约束请求的类型,可以收窄请求范围。指定请求谓词的类型如GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE等
//映射访问路径,必须是POST请求
@RequestMapping(value = "/hello",method = {RequestMethod.POST})
public String index2(Model model){
model.addAttribute("msg", "hello!");
return "test";
}
数据处理
提交的域名称和处理方法的参数名不一致
- 前端提交的name和后端映射器接受的形参名不用一样,再形参前
@RequestParam("xxx")
更改名称一致
前端提交表单域,后端直接使用实体类
- 后端参数封装如果成一个pojo,前端传过来的name会自动pojo中的成员属性,不匹配的属性=null/0
数据显示
ModelAndView
public class ControllerTest1 implements Controller {
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
//返回一个模型视图对象
ModelAndView mv = new ModelAndView();
mv.addObject("msg","ControllerTest1");
mv.setViewName("test");
return mv;
}
}
ModelMap
@RequestMapping("/hello")
public String hello(@RequestParam("username") String name, ModelMap model){
//封装要显示到视图中的数据
//相当于req.setAttribute("name",name);
model.addAttribute("name",name);
return "hello";
}
Model
@RequestMapping("/ct2/hello")
public String hello(@RequestParam("username") String name, Model model){
//封装要显示到视图中的数据
//相当于req.setAttribute("name",name);
model.addAttribute("msg",name);
return "test";
}
Json
对象互转
要实现从JSON字符串转换为JavaScript 对象,使用 JSON.parse() 方法:
var obj = JSON.parse('{"a": "Hello", "b": "World"}');
//结果是 {a: 'Hello', b: 'World'}
要实现从JavaScript 对象转换为JSON字符串,使用 JSON.stringify() 方法:
var json = JSON.stringify({a: 'Hello', b: 'World'});
//结果是 '{"a": "Hello", "b": "World"}'
Jackson
依赖
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.0</version>
</dependency>
控制层
-
@RestControoler: 该类下所有方法不走视图解析器,返回一个json数据 前后端分离使用
-
@ResponseBody:该方法不走视图解析器,返回一个json数据
@Controller
public class UserController {
@RequestMapping("/json1")
@ResponseBody
public String json1() throws JsonProcessingException {
//创建一个jackson的对象映射器,用来解析数据
ObjectMapper mapper = new ObjectMapper();
//创建一个对象
User user = new User("秦疆1号", 3, "男");
//将我们的对象解析成为json格式
String str = mapper.writeValueAsString(user);
//由于@ResponseBody注解,这里会将str转成json格式返回;十分方便
return str;
}
}
FastJson
依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.60</version>
</dependency>
使用
public class FastJsonDemo {
public static void main(String[] args) {
//创建一个对象
User user1 = new User("秦疆1号", 3, "男");
User user2 = new User("秦疆2号", 3, "男");
User user3 = new User("秦疆3号", 3, "男");
User user4 = new User("秦疆4号", 3, "男");
List<User> list = new ArrayList<User>();
list.add(user1);
list.add(user2);
list.add(user3);
list.add(user4);
//Java对象 转 JSON字符串
String str1 = JSON.toJSONString(list);
// JSON字符串 转 Java对象
User jp_user1=JSON.parseObject(str2,User.class);
//Java对象 转 JSON对象
JSONObject jsonObject1 = (JSONObject) JSON.toJSON(user2);
//JSON对象 转 Java对象
User to_java_user = JSON.toJavaObject(jsonObject1, User.class);
}
}
乱码问题
- 单个解决
@RequestMapping(value = "/json1",produces = "application/json;charset=utf-8")
- 配置视图解析器解决
<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>
Json时间工具类
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import java.text.SimpleDateFormat;
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 dateFormat) {
ObjectMapper mapper = new ObjectMapper();
//不使用时间差的方式
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
//自定义日期格式对象
SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
//指定日期格式
mapper.setDateFormat(sdf);
try {
return mapper.writeValueAsString(object);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
}
Ajax
- jquery实现
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
<%--加载动态的JQ资源--%>
<script src="https://code.jquery.com/jquery-3.4.1.js"></script>
<script>
/*
AJax后端必须懂的东西:
url:后端接受的地址
data:后端接受到的请求参数,json数据格式=前后端分离时候,后端传的数据便于前端接受就是json数据
success:后端接受成功返回的函数
error:后盾失败接受返回的函数
*/
function username() {
$.post({
url: "${pageContext.request.contextPath}/a1",
data: {"name": $("#username").val()},
success: function (data, status) {
console.log("data:" + data);
console.log("status:" + status);
}
})
}
</script>
</head>
<body>
<%--实现Ajax异步请求
1 绑定单击事件
2 单击事件函数使用Jq:$.post({})
--%>
用户名:<input type="text" id="username" onclick="username()">
</body>
</html>
- Ajax异步请求
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Ajax</title>
<script src="https://code.jquery.com/jquery-3.4.1.js"></script>
<script>
/*页面加载完*/
$(document).ready(function () {
/*绑定btn单击事件*/
$("#btn").click(function () {
/*JQ使用Ajax异步请求*/
$.post("${pageContext.request.contextPath}/a2", function (data) {
// data接受返回的值
//console.log(data);
var html = "";
for (let i = 0; i < data.length; i++) {
html += "<tr>" +
"<td>" + data[i].name + "</td>" +
"<td>" + data[i].age + "</td>" +
"<td>" + data[i].sex + "</td>" +
+"<tr>"
}
$("#content").html(html);
});
});
})
</script>
</head>
<body>
<input type="button" id="btn" value="加载数据">
<table>
<tr>
<td>姓名</td>
<td>年龄</td>
<td>性别</td>
</tr>
<tbody id="content">
</tbody>
</table>
</body>
</html>
- Ajax登录验证
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>login</title>
<script src="https://code.jquery.com/jquery-3.4.1.js"></script>
<script>
function nameFun() {
$.post({
url: "${pageContext.request.contextPath}/a3",
data: {"name": $("#name").val()},
success: function (data) {
//console.log(data);
if (data.toString() === "用户名成功") {
$("#userInfo").css("color", "green");
} else {
$("#userInfo").css("color", "red");
}
$("#userInfo").html(data);
}
})
}
function passwordFun() {
$.post({
url: "${pageContext.request.contextPath}/a3",
data: {"password": $("#password").val()},
success: function (data) {
if (data.toString() === "密码正确") {
$("#userPasswordInfo").css("color", "green");
}else {
$("#userPasswordInfo").css("color", "red");
}
$("#userPasswordInfo").html(data);
}
})
}
</script>
</head>
<body>
<p>
用户名:<input type="text" id="name" onclick="nameFun()">
<%--span提示信息--%>
<span id="userInfo"></span>
</p>
<p>
用户密码:<input type="password" id="password" onclick="passwordFun()">
<span id="userPasswordInfo"></span>
</p>
</body>
</html>
- Json乱码解决
<?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
https://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">
<!--1 自动扫描包,让指定包下的注解生效,由IOC容器统一管理-->
<context:component-scan base-package="com.nuc.controller"/>
<!--2 注解驱动-->
<mvc:annotation-driven/>
<!-- 使用JQ,使用静态资源过滤需要引用,动态就不需要-->
<mvc:default-servlet-handler/>
<!--注解加载映射器、适配器,解决Json数据中文乱码问题-->
<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>
<!--3 以上的是定死的代码,以下是配置视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
拦截器
- 数据独立性:Servlet中的是过滤器,而拦截器是SpringMVC框架独有的,独享request和response
- 拦截器只会拦截访问的控制器方法,如果访问的是jsp/html/css等式不会拦截的
- 拦截器是基于AOP思想的,和AOP实现是一样的,在application.xml中配置
<!--拦截器配置-->
<mvc:interceptors>
<mvc:interceptor>
<!--
/**是拦截之后所有的请求,比如/admin/a1/2131
-->
<mvc:mapping path="/**"/>
<bean class="com.nuc.config.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
- 具体拦截内容
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//return true:执行下一个拦截器
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("===========清洁中=================");
}
}
- eg(登录拦截)
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HttpSession session = request.getSession();
request.getRequestURL();
//URL:http://localhost:8080/springmvc_07_interceptor/user//main
System.out.println("URL:" + request.getRequestURL());
//URI:/springmvc_07_interceptor/user//main
System.out.println("URI:" + request.getRequestURI());
if (session.getAttribute("username") == null || session.getAttribute("password") == null) {
request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
} else if (session.getAttribute("username").equals("admin") && session.getAttribute("password").equals("123456")) {
return true;
}
if (request.getRequestURI().contains("ogin")) {
return true;
}
request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
return false;
}
}
文件上传&下载
- application.xml配置
<!--文件上传配置-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 请求的编码格式,必须和jSP的pageEncoding属性一致,以便正确读取表单的内容,默认为ISO-8859-1 -->
<property name="defaultEncoding" value="utf-8"/>
<!-- 上传文件大小上限,单位为字节(10485760=10M) -->
<property name="maxUploadSize" value="10485760"/>
<property name="maxInMemorySize" value="40960"/>
</bean>
- Controller编写
@RestController
public class FileController {
@RequestMapping("/upload")
public String upFile(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) throws IOException {
//设置文件保存路径
String path = request.getServletContext().getRealPath("/upload");
System.out.println("path:" + path);
File realPath = new File(path);
if (!realPath.exists()) {
realPath.mkdir();
}
System.out.println("上传的文件地址:" + realPath);
//CommonsMultipartFile的方法写文件,简化
file.transferTo(new File(realPath + "/" + file.getOriginalFilename()));
return "redirect:/index.jsp";
}
@RequestMapping("/upload2")
public String fileUpload(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) throws IOException {
//获取文件名 : file.getOriginalFilename();
String uploadFileName = file.getOriginalFilename();
//如果文件名为空,直接回到首页!
if ("".equals(uploadFileName)) {
return "redirect:/index.jsp";
}
System.out.println("上传文件名 : " + uploadFileName);
//上传路径保存设置
String path = request.getServletContext().getRealPath("/upload");
//如果路径不存在,创建一个
File realPath = new File(path);
if (!realPath.exists()) {
realPath.mkdir();
}
System.out.println("上传文件保存地址:" + realPath);
InputStream is = file.getInputStream(); //文件输入流
OutputStream os = new FileOutputStream(new File(realPath, uploadFileName)); //文件输出流
//读取写出
int len = 0;
byte[] buffer = new byte[1024];
while ((len = is.read(buffer)) != -1) {
os.write(buffer, 0, len);
os.flush();
}
os.close();
is.close();
return "redirect:/index.jsp";
}
@RequestMapping(value="/download")
public String downloads(HttpServletResponse response , HttpServletRequest request) throws Exception{
//要下载的图片地址
String path = request.getServletContext().getRealPath("/upload");
String fileName = "白帝学园.zip";
//1、设置response 响应头
response.reset(); //设置页面不缓存,清空buffer
response.setCharacterEncoding("UTF-8"); //字符编码
response.setContentType("multipart/form-data"); //二进制传输数据
//设置响应头
response.setHeader("Content-Disposition",
"attachment;fileName="+ URLEncoder.encode(fileName, "UTF-8"));
File file = new File(path,fileName);
//2、 读取文件--输入流
InputStream input=new FileInputStream(file);
//3、 写出文件--输出流
OutputStream out = response.getOutputStream();
byte[] buff =new byte[1024];
int index=0;
//4、执行 写出操作
while((index= input.read(buff))!= -1){
out.write(buff, 0, index);
out.flush();
}
out.close();
input.close();
return null;
}
}
- 前端页面
<form enctype="multipart/form-data" method="post" action="${pageContext.request.contextPath}/upload">
<input type="file" name="file"/>
<input type="submit" value="upload">
</form>
<a href="/download">点击下载</a>
@ModelAttribute
解决修改中为赋值对象为空的问题
-
利用隐藏域,在用户进行修改的时候,将对应的不能修改的字段进行隐藏
-
先从数据库中将用户信息给读取出来,然后将不能修改的字段重新进行赋值然后更新
-
@ModelAttribute注解,springmvc提前执行取数据操作,再进行修改操作
使用总结
1、注解在没有返回值的方法上面
就如上面的例子注解在没有返回值的方法上面,用在POJO入参上面,或者我们可以在这里设定一些Request域中的对象,在前台可以直接使用。
@ModelAttribute
public void getUser(){
maps.put("name", "zhangsan");
}
2、注解在有返回值的方法上面,
这里要用value属性进行数据存储,会将返回值存储在value属性的值中,可以在前台直接获取。
@ModelAttribute(value="user00")
public User testModelAttribute(){
User user =new User(1,"tom00", 12,"ff@163.com", "123400");
return user;
}
3、在方法参数上使用@ModelAttribute
在方法的参数中使用必须是修饰POJO类,这样的话,才能从相应的域中获取数据
@RequestMapping("/TestModelArributes")
public String TestModelArributes(@ModelAttribute( value="change") User user){
System.out.println("打印"+user);
return SUCCESS;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!