1、MVC常用
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.注册DispatcherServlet-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--关联一个springmvc的配置文件:【servlet-name】-servlet.xml-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
<!--启动级别-1-->
<load-on-startup>1</load-on-startup>
</servlet>
<!--/ 匹配所有的请求;(不包括.jsp)-->
<!--/* 匹配所有的请求;(包括.jsp)-->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<filter>
<filter-name>encoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<!--解决乱码-->
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
/ 和 / 的区别:< url-pattern > / </ url-pattern > 不会匹配到.jsp, 只针对我们编写的请求;即:.jsp 不会进入spring的 DispatcherServlet类 。< url-pattern > / </ url-pattern > 会匹配 *.jsp,会出现返回 jsp视图时再次进入spring的DispatcherServlet 类,导致找不到对应的controller所以报404错
springmvc-servlet.xml:
在resources中配置,SpringMVC的核心配置文件
<?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" xmlns:mv="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">
<!-- 自动扫描包,让指定包下的注解生效,由IOC容器统一管理 -->
<context:component-scan base-package="com.qing.controller"/>
<!-- 让Spring MVC不处理静态资源 .css .js .html等-->
<mvc:default-servlet-handler/>
<!-- 视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
id="internalResourceViewResolver">
<!-- 前缀 -->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!-- 后缀 -->
<property name="suffix" value=".jsp"/>
</bean>
<!--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>
<!-- 拦截器配置-->
<mv:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.qing.interceptor.MtInterceptor"/>
</mvc:interceptor>
</mv:interceptors>
</beans>
第23行的路径一定要对应WEB-INF下的jsp
常用的jar包
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.6</version>
</dependency>
2、回顾servlet
1.1 创建web项目
1.2 导包
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
1.3 配置servlet
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("/jsp/test.jsp").forward(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
1.4 配置web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.qing.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>form.jsp</welcome-file>
</welcome-file-list>
</web-app>
3、第一个SpringMVC程序
创建项目,添加web框架支持
编写web.xml配置文件
编写springmvc-servlet.xml配置文件 ```xml <?xml version=”1.0” encoding=”UTF-8”?>
<!--Handler-->
<bean id="/hello" class="com.qing.controller.HelloController"/>
-
编写一个hello.jsp页面
-
编写HelloController控制
```java
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//注意:这里我们先导入Controller接口
public class HelloController implements Controller {
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
//ModelAndView 模型和视图
ModelAndView mv = new ModelAndView();
//业务代码
String result = "HelloSpringMVC";
//封装对象,放在ModelAndView中 ,Model
mv.addObject("msg", result);
//封装要跳转的视图,放在ModelAndView中
mv.setViewName("hello"); //: /WEB-INF/jsp/hello.jsp
return mv;
}
}
出现问题:
如果出现了404页面错误,在代码逻辑没有出错的情况下,检查Artifacts下有没有lib依赖,若没有,则需添加
4、使用注解开发
创建项目,添加web框架支持
编写web.xml配置文件
编写springmvc-servlet.xml配置文件 ```xml <?xml version=”1.0” encoding=”UTF-8”?>
<!-- 自动扫描包,让指定包下的注解生效,由IOC容器统一管理 -->
<context:component-scan base-package="com.qing.controller"/>
<!-- 让Spring MVC不处理静态资源 .css .js .html等-->
<mvc:default-servlet-handler />
<!--
支持mvc注解驱动
在spring中一般采用@RequestMapping注解来完成映射关系
要想使@RequestMapping注解生效
必须向上下文中注册DefaultAnnotationHandlerMapping
和一个AnnotationMethodHandlerAdapter实例
这两个实例分别在类级别和方法级别处理。
而annotation-driven配置帮助我们自动完成上述两个实例的注入。
-->
<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>
-
编写一个hello.jsp页面
-
编写HelloController控制
```java
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
//在类上添加@controller注解后,这个类才会被视图解析器解析
@Controller
public class HelloController {
@RequestMapping("/hello") //网页请求http://localhost:8080/SpringMVC_03_annotation_war_exploded/hello时
public String hello(Model model){
//封装数据
model.addAttribute("msg","Hello,SpringMVC!");
return "hello"; //会被视图解析器处理 经过封装后显示对应的/WEB-INF/jsp/hello.jsp页面
}
}
5、RestFul风格
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
@Controller
public class RestFulController {
//原来的路径请求为:http://localhost:8080/SpringMVC_03/add?a=1&b=2
//使用restful风格的路径请求为:http://localhost:8080/SpringMVC_03/add/1/2 (常用)
//可以自定义请求方式 get、post等
// @RequestMapping(value = "/add/{a}/{b}",method = RequestMethod.GET)
@RequestMapping("/add/{a}/{b}")
// @GetMapping("/add/{a}/{b}")
// @PostMapping("/add/{a}/{b}")
public String add(@PathVariable int a, @PathVariable int b, Model model) {
//@PathVariable 代表参数为路径参数
int res = a + b;
model.addAttribute("msg", "结果为" + res);
return "add";
}
}
RestFul风格使用安全,他人分辨不出参数的意义;而使用原始传参,add?a=1&b=2就可以清楚的分辨
6、重定向与转发
区别:
转发是服务器行为,只需一次跳转,用户看不到url地址上的变化。重定向是游览器端的行为,需要进行二次跳转,用户能看到url地址上的变化。
转发的速度比重定向的速度相对要高,因为转发只需要做一次请求,而重定向需要做二次请求。
转发能够获取request作用域中的数据,他只发出了一次请求,而重定向无法获取request中的数据 ,因为他发出了二次请求,每一次请求对应着一次新的request
转发只能访问当前服务器中的数据,而重定向可以访问任意服务器中的数据
转发不能解决数据的重复提交问题(就是能按F5进行刷新操作),而重定向能解决数据的重复提交。
语句:
- 原生转发:request.getRequestDispatcher(“路径”).forward(request, response);
- 原生重定向:response.sendRedirect(“路径”);
- SpringMvc转发:forward:/路径
- SpringMvc重定向:redirect:/路径
测试:
@Controller
public class ViewModel {
@RequestMapping("/v")
public String view1(Model model){
model.addAttribute("msg", "ViewModel");
// return "forward:/index.jsp"; //转发
return "redirect:/toIndex"; //重定向 走对应的toIndex请求,再从toIndex请求中二次跳转到index.jsp页面
}
@RequestMapping("/toIndex")
public String view2(Model model){
model.addAttribute("msg", "ViewModel");
return "index"; //二次跳转至index.jsp页面
}
}
7、前端接收数据以及回显
@Controller
@RequestMapping("/user")
public class UserController {
//http://localhost:8080/SpringMVC_03/user/u1?&username=qing
@RequestMapping("u1")
public String test1(@RequestParam("username") String name, Model model) {
//@RequestParam代表了前端传参的参数名,固定的
//接收前端参数
System.out.println("前端参数为:" + name);
//将结果返回前端
model.addAttribute("msg",name);
//视图跳转
return "hello";
}
//前端接收的是一个对象时:id name age
//http://localhost:8080/SpringMVC_03/user/u2?id=1&name=qing&age=18
@RequestMapping("u2")
public String test2(User user,Model model){
System.out.println(user.toString());
model.addAttribute("msg",user);
return "hello";
}
}
8、解决乱码
方法一:自定义过滤器
编写EncodingFilter类:
import javax.servlet.*;
import java.io.IOException;
public class EncodingFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
chain.doFilter(request,response);
}
@Override
public void destroy() {
}
}
配置web.xml:
<filter>
<filter-name>encoding</filter-name>
<filter-class>com.qing.filter.EncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
**注:这里第8行必须使用 / 才能使过滤器生效,过滤到所有的jsp页面
方式二:spring自带过滤器(建议使用)
配置web.xml:
<filter>
<filter-name>encoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
方式三:万能的过滤器(大佬编写)
自定义类:
/**
* 解决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) throws ServletException {
}
}
//自定义request对象,HttpServletRequest的包装类
class MyRequest extends HttpServletRequestWrapper {
private 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();
String[] values = parameterMap.get(name);
return values;
}
}
配置web.xml:
<filter>
<filter-name>encoding</filter-name>
<filter-class>com.qing.filter.GenericEncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
9、Jackson(推荐)
导包:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.3</version>
</dependency>
9.1 格式转换
<script type="text/javascript">
//编写一个JavaScript对象
var user={
name:"卿帆",
age:20,
sex:"男"
}
//控制台输出
console.log(user);
//将js对象、数组转换为字符串
var obj=JSON.stringify(user);
console.log(obj);
//将字符串转换为json对象
var json=JSON.parse(obj);
console.log(json)
</script>
9.2 后端传送数据给前端
测试单个对象:
// @RestController
@Controller
public class UserController {
@RequestMapping("/j1")
@ResponseBody //添加此注解后不会走视图解析器,直接返回一个字符串 配合@controller使用;也可以使用@RestController直接返回字符串
public String json1() throws JsonProcessingException {
ObjectMapper mapper=new ObjectMapper();
User user=new User("qingfan",20,"男");
String string = mapper.writeValueAsString(user); //生成json字符串
return string;
}
}
测试集合:
@RequestMapping("/j2")
@ResponseBody //添加此注解后不会走视图解析器,直接返回一个字符串
public String json2() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
User user1 = new User("卿", 20, "男");
User user2 = new User("陈", 20, "女");
User user3 = new User("帆", 20, "男");
User user4 = new User("莹", 20, "女");
List<User> users = new ArrayList<>();
users.add(user1);
users.add(user2);
users.add(user3);
users.add(user4);
String string = mapper.writeValueAsString(users); //生成json字符串
return string;
}
测试时间:
@RequestMapping("/j3")
@ResponseBody //添加此注解后不会走视图解析器,直接返回一个字符串
public String json3() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
/*
//默认使用时间戳
//自定义时间格式
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date data = new Date();
String string = mapper.writeValueAsString(sf.format(date););
return string;
*/
//不使用时间戳的方式格式化时间
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
//自定义时间格式
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
mapper.setDateFormat(sf);
Date data = new Date();
String string = mapper.writeValueAsString(data);
return string;
}
9.3 前端出现乱码
解决方式一:
将@RequestMapping("/j1")更改为:
@RequestMapping(value = "/j1",produces = "application/json;charset=utf-8")
方式二:在spring配置文件中配置
<!--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>
9.4 抽象JsonUtils工具类
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 sf = new SimpleDateFormat(dateFormat);
mapper.setDateFormat(sf);
try {
return mapper.writeValueAsString(object);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
}
10、Fastjson
导包:
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.76</version>
</dependency>
测试:
@RequestMapping("/j3")
@ResponseBody
public String json3() {
User user1 = new User("卿", 20, "男");
User user2 = new User("陈", 20, "女");
User user3 = new User("帆", 20, "男");
User user4 = new User("莹宝", 20, "女");
List<User> users = new ArrayList<>();
users.add(user1);
users.add(user2);
users.add(user3);
users.add(user4);
return JSON.toJSONString(users);
}
11、拦截器
自定义拦截器类:
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MtInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HttpSession session = request.getSession();
//判断登录情况
if(request.getRequestURI().contains("login")){
return true;
}
if(session.getAttribute("userLoginInfo")!=null){
return true;
}
//没有登录时 跳转到登录页面
request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request,response);
return false;
}
//下面2个方法可以省略
@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配置文件
<!-- 拦截器配置-->
<mv:interceptors>
<mvc:interceptor>
<!-- /** 是拦截根目录下的所有请求-->
<mvc:mapping path="/**"/>
<bean class="com.qing.interceptor.MtInterceptor"/>
</mvc:interceptor>
</mv:interceptors>
12、文件上传和下载
12.1 上传
导包:
<!--文件上传需要导入的jar包-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
<!--servlet必须使用高版本的javax.servlet-api-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
</dependencies>
编写Spring配置文件:
<!--文件上传配置-->
<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>
编写FileController:
@RestController
public class FileController {
//@RequestParam("file") 将name=file控件得到的文件封装成CommonsMultipartFile 对象
//批量上传CommonsMultipartFile则为数组即可
@RequestMapping("/upload")
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";
}
/*
* 方式二 采用file.Transto 来保存上传的文件
*/
@RequestMapping("/upload2")
public String fileUpload2(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) throws IOException {
//上传路径保存设置
String path = request.getServletContext().getRealPath("/upload");
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";
}
}
12.2 下载
@RequestMapping("/download")
@ResponseBody
public String downloads(HttpServletResponse response , HttpServletRequest request) throws Exception{
System.out.println("downloads():");
//要下载的图片地址
String path = request.getServletContext().getRealPath("/upload");
String fileName = "1.jpg";
//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 "ok";
}
13、SpringMvc扩展(面试)
13.1 MVC工作流程
流程详解:
- 用户发送出请求到前端控制器DispatcherServlet。
- DispatcherServlet收到请求调用HandlerMapping(处理器映射器)。
- HandlerMapping找到具体的Handler(可查找xml配置或注解配置),生成处理器对象的执行链(如果有),再一起返回给DispatcherServlet。
- DispatcherServlet调用HandlerAdapter(处理器适配器)。
- HandlerAdapter经过适配调用具体的处理器(controller)。
- Controller执行完成返回ModelAndView对象。
- HandlerAdapter将Controller执行结果ModelAndView返回给DispatcherServlet。
- DispatcherServlet将ModelAndView传给ViewReslover(视图解析器)。
- ViewReslover解析后返回具体View(视图)。
- DispatcherServlet根据View进行渲染视图(即将数据填充至视图中)。
- DispatcherServlet响应用户。
设计组件分析:
1、前端控制器DispatcherServlet(不需要程序员开发),由框架提供,在web.xml中配置。
作用:接收请求,响应结果,相当于转发器,中央处理器。
2、处理器映射器HandlerMapping(不需要程序员开发),由框架提供。
作用:根据请求的url查找Handler(处理器/Controller),可以通过XML和注解方式来映射。
3、处理器适配器HandlerAdapter(不需要程序员开发),由框架提供。
作用:按照特定规则(HandlerAdapter要求的规则)去执行Controller。
4、控制器Controller(需要工程师开发)
注意:编写Handler时按照HandlerAdapter的要求去做,这样适配器才可以去正确执行Handler。
作用:接受用户请求信息,调用业务方法处理请求,也称之为后端控制器。
5、视图解析器ViewResolver(不需要程序员开发),由框架提供
作用:进行视图解析,把逻辑视图名解析成真正的物理视图。
SpringMVC框架支持多种View视图技术,包括:jstlView、freemarkerView、pdfView等。
6、视图View(需要工程师开发)
作用:把数据展现给用户的页面
View是一个接口,实现类支持不同的View技术(jsp、freemarker、pdf等)
13.2 MVC九大组件
- HandlerMapping
处理器映射器,对应的初始化方法是initHandlerMappings(context),这就是根据用户请求的资源uri来查找Handler的。在SpringMVC中会有很多请求,每个请求都需要一个Handler处理,HandlerMapping就解决具体接收到一个请求之后使用哪个Handler进行处理 - HandlerAdapter
对应的初始化方法是initHandlerAdapters(context),从名字上看,它就是一个适配器。因为SpringMVC中的Handler可以是任意的形式,只要能处理请求就ok,但是Servlet需要的处理方法的结构却是固定的,都是以request和response为参数的方法。HandlerAdapter解决如何让固定的Servlet处理方法调用灵活的Handler来进行处理
小结:Handler是用来干活的工具;HandlerMapping用于根据需要干的活找到相应的工具;HandlerAdapter是使用工具干活的人。 - HandlerExceptionResolver:根据异常设置ModelAndView,之后再交给render方法进行渲染
- ViewResolver:找到渲染所用的模板和所用的技术(也就是视图的类型)进行渲染
- RequestToViewNameTranslator:从request中获取ViewName
- LocaleResolver:解决语言国际化,从request解析出Locale
- ThemeResolver:⽤来解析主题
- MultipartResolver:⽤于上传请求
- FlashMapManager:⽤于重定向时的参数传递
13.3 MVC控制器是不是单例模式
- 控制器是单例模式
MVC如何保证线程安全:
- 不要在controller中定义成员变量,最好将控制器设计成无状态模式
- 万一必须要定义一个非静态成员变量时候,则通过注解@Scope(“prototype”),将其设置为多例
- 在Controller中调用成员变量Service也不会造成线程安全问题:因为只是调用Service里的方法,方法都是线程安全的,多线程调用一个实例的方法,会在内存中复制变量,所以只要不在Constroller里修改Service这个实例就没问题