springMVC详细教程

jsp 代码:

<!-- requestParams 注解的使用 -->
<a href="springmvc/useRequestParam?name=test">requestParam 注解</a>

控制器代码:

@RequestMapping("/useRequestParam")
public String useRequestParam(@RequestParam("name")String username,
@RequestParam(value="age",required=false)Integer age){
	System.out.println(username+","+age);
	return "success";
}

2. RequestBody

使用说明
  • 作用: 用于获取请求体内容。直接使用得到是 key=value&key=value…结构的数据。get 请求方式不适用。
  • 属性:
    required:是否必须有请求体。默认值是:true。当取值为 true 时,get 请求方式会报错。如果取值为 false,get 请求得到是 null。
示例

jsp代码:

<!-- request body 注解 -->
<form action="springmvc/useRequestBody" method="post">
	用户名称:<input type="text" name="username" ><br/>
	用户密码:<input type="password" name="password" ><br/>
	用户年龄:<input type="text" name="age" ><br/>
	<input type="submit" value="保存">
</form>

控制器代码:

@RequestMapping("/useRequestBody")
public String useRequestBody(@RequestBody(required=false) String body){
	System.out.println(body);
	return "success";
}

在这里插入图片描述

3. PathVaribale

使用说明
  • 作用: 用于绑定 url 中的占位符。例如:请求 url 中 /delete/{id},这个{id}就是 url 占位符。
    url 支持占位符是 spring3.0 之后加入的。是 springmvc 支持 rest 风格 URL 的一个重要标志。
  • 属性:
    value:用于指定 url 中占位符名称,只有此一个属性时value可省略不写,直接写占位符名称。
    required:是否必须提供占位符。
示例

jsp 代码:

<!-- PathVariable 注解 -->
<a href="springmvc/usePathVariable/100">pathVariable 注解</a>

控制器代码:

@RequestMapping("/usePathVariable/{id}")
public String usePathVariable(@PathVariable("id") Integer id){
	System.out.println(id);
	return "success";
}

4. RequestHeader

使用说明
  • 作用: 用于获取请求消息头。
  • 属性:
    value:提供消息头名称
    required:是否必须有此消息头

(在实际开发中一般不常用该注解)

示例

jsp 代码:

<!-- RequestHeader 注解 -->
<a href="springmvc/useRequestHeader">获取请求消息头</a>

控制器代码:

@RequestMapping("/useRequestHeader")
public String useRequestHeader(@RequestHeader(value="Accept-Language",required=false)String requestHeader){
	System.out.println(requestHeader);
	return "success";
}

5. CookieValue

使用说明
  • 作用: 用于把指定 cookie 名称的值传入控制器方法参数。
  • 属性:
    value:指定 cookie 的名称。
    required:是否必须有此 cookie。
示例

jsp 代码:

<!-- CookieValue 注解 -->
<a href="springmvc/useCookieValue">绑定 cookie 的值</a>

控制器代码:

@RequestMapping("/useCookieValue")
public String useCookieValue(@CookieValue(value="JSESSIONID",required=false) String cookieValue){
	System.out.println(cookieValue);
	return "success";
}

6. ModelAttribute

使用说明
  • 作用:
    该注解是 SpringMVC4.3 版本以后新加入的。它可以用于修饰方法和参数。
    a) 用方法上:表示当前方法会在控制器的方法执行之前,先执行。它可以修饰没有返回值的方法,也可以修饰有具体返回值的方法。
    b) 用参数上:获取指定的数据给参数赋值。
  • 属性:
    value:用于获取数据的 key。key 可以是 POJO 的属性名称,也可以是 map 结构的 key。
  • 应用场景:
    当表单提交数据不是完整的实体类数据时,保证没有提交数据的字段使用数据库对象原来的数据。
    例如:
    我们在编辑一个用户时,用户有一个创建信息字段,该字段的值是不允许被修改的。在提交表单数
    据是肯定没有此字段的内容,一旦更新会把该字段内容置为 null,此时就可以使用此注解解决问题。
使用示例
示例1:基于 POJO 属性

jsp代码:

<a href="springmvc/testModelAttribute?username=test">测试 modelattribute</a>

控制器代码:

/\*\*
\* 被 ModelAttribute 修饰的方法
\*/
@ModelAttribute
public void showModel(User user) {
	System.out.println("执行了 showModel 方法"+user.getUsername());
}
/\*\*
\* 接收请求的方法
\*/
@RequestMapping("/testModelAttribute")
public String testModelAttribute(User user) {
	System.out.println("执行了控制器的方法"+user.getUsername());
	return "success";
}

在这里插入图片描述

示例2:基于 Map 的应用场景:ModelAttribute 修饰方法带返回值

需求:修改用户信息,要求用户的密码不能修改

jsp 的代码:

<!-- 修改用户信息 -->
<form action="springmvc/updateUser" method="post">
	用户名称:<input type="text" name="username" ><br/>
	用户年龄:<input type="text" name="age" ><br/>
	<input type="submit" value="保存">
</form>

控制器代码:

/\*\*
\* 查询数据库中用户信息
\*/
@ModelAttribute
public User showModel(String username) {
	//模拟去数据库查询
	User abc = findUserByName(username);
	System.out.println("执行了 showModel 方法"+abc);
	return abc;
}
/\*\*
\* 模拟修改用户方法
\*/
@RequestMapping("/updateUser")
public String testModelAttribute(User user) {
	System.out.println("控制器中处理请求的方法:修改用户:"+user);
	return "success";
}
/\*\*
\* 模拟去数据库查询
\*/
private User findUserByName(String username) {
	User user = new User();
	user.setUsername(username);
	user.setAge(19);
	user.setPassword("123456");
	return user;
}

在这里插入图片描述

示例3:基于 Map 的应用场景:ModelAttribute 修饰方法不带返回值

需求:修改用户信息,要求用户的密码不能修改

jsp 的代码:

<!-- 修改用户信息 -->
<form action="springmvc/updateUser" method="post">
	用户名称:<input type="text" name="username" ><br/>
	用户年龄:<input type="text" name="age" ><br/>
	<input type="submit" value="保存">
</form>

控制器代码:

/\*\*
\* 查询数据库中用户信息
\*/
@ModelAttribute
public void showModel(String username, Map<String,User> map) {
	//模拟去数据库查询
	User user = findUserByName(username);
	System.out.println("执行了 showModel 方法"+user);
	map.put("abc",user);
}

/\*\*
\* 模拟修改用户方法
\*/
@RequestMapping("/updateUser")
public String testModelAttribute(@ModelAttribute("abc")User user) {
	System.out.println("控制器中处理请求的方法:修改用户:"+user);
	return "success";
}

/\*\*
 \* 模拟去数据库查询
\*/
private User findUserByName(String username) {
	User user = new User();
	user.setUsername(username);
	user.setAge(19);
	user.setPassword("123456");
	return user;
}

在这里插入图片描述

7. SessionAttribute

使用说明
  • 作用: 用于多次执行控制器方法间的参数共享
  • 属性:
    value:用于指定存入的属性名称
    type:用于指定存入的数据类型。
示例

jsp代码:

<!-- SessionAttribute 注解的使用 -->
<a href="springmvc/testPut">存入 SessionAttribute</a>
<hr/>
<a href="springmvc/testGet">取出 SessionAttribute</a>
<hr/>
<a href="springmvc/testClean">清除 SessionAttribute</a>

控制器代码:

@Controller("sessionAttributeController")
@RequestMapping("/springmvc")
@SessionAttributes(value ={"username","password", "age"}, types={String.class, Integer.class}) 
public class SessionAttributeController {
	/\*\*
 \* 把数据存入 SessionAttribute
 \* Model 是 spring 提供的一个接口,该接口有一个实现类 ExtendedModelMap
 \* 该类继承了 ModelMap,而 ModelMap 就是 LinkedHashMap 子类
 \*/
	@RequestMapping("/testPut") 
	public String testPut(Model model){ 
		System.out.println("向session域中保存数据");
		model.addAttribute("username", "泰斯特"); 
		model.addAttribute("password","123456"); 
		model.addAttribute("age", 31); 
		//跳转之前将数据保存到 username、password 和 age 中,因为注解@SessionAttribute 中有这几个参数 
		return "success"; 
	 } 
	 /\*\*
 \* 从session中获取值
 \*/
	 @RequestMapping("/testGet") 
	 public String testGet(ModelMap model){  
		System.out.println(model.get("username")+";"+model.get("password")+";"+model.get("age")); 
		return "success"; 
	 } 
	 /\*\*
 \* 清除值
 \*/
	 @RequestMapping("/testClean") 
	 public String complete(SessionStatus sessionStatus){ 
		 sessionStatus.setComplete(); 
		 return "success"; 
	 } 
}


六、REST 风格 URL

什么是rest ?

REST(英文:Representational State Transfer,简称 REST)描述了一个架构样式的网络系统,
比如 web 应用程序。它首次出现在 2000 年 Roy Fielding 的博士论文中,他是 HTTP 规范的主要编写者之
一。在目前主流的三种 Web 服务交互方案中,REST 相比于 SOAP(Simple Object Access protocol,简单
对象访问协议)以及 XML-RPC 更加简单明了,无论是对 URL 的处理还是对 Payload 的编码,REST 都倾向于用更加简单轻量的方法设计和实现。值得注意的是 REST 并没有一个明确的标准,而更像是一种设计的风格。
它本身并没有什么实用性,其核心价值在于如何设计出符合 REST 风格的网络接口。

restful优点

它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用。

restful 的特性

  • 资源(Resources):
    网络上的一个实体,或者说是网络上的一个具体信息。
    它可以是一段文本、一张图片、一首歌曲、一种服务,总之就是一个具体的存在。可以用一个 URI(统一
    资源标识符)指向它,每种资源对应一个特定的 URI 。要获取这个资源,访问它的 URI 就可以,因此 URI 即为每一个资源的独一无二的识别符。
  • 表现层(Representation):
    把资源具体呈现出来的形式,叫做它的表现层 (Representation)。
    比如,文本可以用 txt 格式表现,也可以用 HTML 格式、XML 格式、JSON 格式表现,甚至可以采用二进制格式。
  • 状态转化(State Transfer):
    每发出一个请求,就代表了客户端和服务器的一次交互过程。
    HTTP 协议,是一个无状态协议,即所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,
    必须通过某种手段,让服务器端发生“状态转化”(State Transfer)。而这种转化是建立在表现层之上的,所以
    就是 “表现层状态转化”。具体说,就是 HTTP 协议里面,四个表示操作方式的动词:GET 、POST 、PUT、
    DELETE。它们分别对应四种基本操作:GET 用来获取资源,POST 用来新建资源,PUT 用来更新资源,DELETE 用来删除资源。

restful 的示例:

  • /account/1 HTTP GET : 得到 id = 1 的 account
  • /account/1 HTTP DELETE: 删除 id = 1 的 account
  • /account/1 HTTP PUT: 更新 id = 1 的 account
  • /account HTTP POST: 新增 account

基于 HiddentHttpMethodFilter 的示例

  • 作用:
    由于浏览器 form 表单只支持 GET 与 POST 请求,而 DELETE、PUT 等 method 并不支持,Spring3.0 添
    加了一个过滤器,可以将浏览器请求改为指定的请求方式,发送给我们的控制器方法,使得支持 GET、POST、PUT 与 DELETE 请求。
  • 使用方法:
    第一步:在 web.xml 中配置该过滤器。
    第二步:请求方式必须使用 post 请求。
    第三步:按照要求提供_method 请求参数,该参数的取值就是我们需要的请求方式。

jsp代码:

<!-- 保存 -->
<form action="springmvc/testRestPOST" method="post">
	用户名称:<input type="text" name="username"><br/>
	<!-- <input type="hidden" name="\_method" value="POST"> -->
	<input type="submit" value="保存">
</form>
<hr/>
<!-- 更新 -->
<form action="springmvc/testRestPUT/1" method="post">
	用户名称:<input type="text" name="username"><br/>
	<input type="hidden" name="\_method" value="PUT">
	<input type="submit" value="更新">
</form>
<hr/>
<!-- 删除 -->
<form action="springmvc/testRestDELETE/1" method="post">
	<input type="hidden" name="\_method" value="DELETE">
	<input type="submit" value="删除">
</form>
<hr/>
<!-- 查询一个 -->
<form action="springmvc/testRestGET/1" method="post">
	<input type="hidden" name="\_method" value="GET">
	<input type="submit" value="查询">
</form>

控制器代码:

/\*\*
\* post 请求:保存
\*/
@RequestMapping(value="/testRestPOST", method=RequestMethod.POST)
public String testRestfulURLPOST(User user){
	System.out.println("rest post"+user);
	return "success";
}

/\*\*
\* put 请求:更新
\*/
@RequestMapping(value="/testRestPUT/{id}",method=RequestMethod.PUT)
public String testRestfulURLPUT(@PathVariable("id")Integer id, User user){
	System.out.println("rest put "+id+","+user);
	return "success";
}

/\*\*
\* post 请求:删除
\*/
@RequestMapping(value="/testRestDELETE/{id}", method=RequestMethod.DELETE)
public String testRestfulURLDELETE(@PathVariable("id")Integer id){
	System.out.println("rest delete "+id);
	return "success";
}

/\*\*
\* post 请求:查询
\*/
@RequestMapping(value="/testRestGET/{id}",method=RequestMethod.GET)
public String testRestfulURLGET(@PathVariable("id")Integer id){
	System.out.println("rest get "+id);
	return "success";
}

在这里插入图片描述


七、响应数据和结果视图

7.1 返回值分类

7.1.1 字符串

controller 方法返回字符串可以指定逻辑视图名,通过视图解析器解析为物理视图地址。
例如:

//指定逻辑视图名,经过视图解析器解析为 jsp 物理路径:/WEB-INF/pages/success.jsp
@RequestMapping("/testReturnString")
public String testReturnString() {
System.out.println("AccountController 的 testReturnString 方法执行了。。。。");
return "success";
}

7.1.2 void

通过前面我们知道, Servlet 原始 API 可以作为控制器中方法的参数:

@RequestMapping("/testReturnVoid")
public void testReturnVoid(HttpServletRequest request,HttpServletResponse response) 
throws Exception {
}

在 controller 方法形参上可以定义 request 和 response,使用 request 或 response 指定响应结果:

  • 1、使用 request 转发页面,如下:
request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request, response);

  • 2、通过 response 页面重定向
response.sendRedirect("testRetrunString")

  • 3、也可以通过 response 指定响应结果,例如响应 json 数据:
response.setCharacterEncoding("utf-8");
response.setContentType("application/json;charset=utf-8");
response.getWriter().write("json 串");

7.1.3 ModelAndView

ModelAndView 是 SpringMVC 为我们提供的一个对象,该对象也可以用作控制器方法的返回值,可以用来调整具体的JSP视图。该对象中有两个方法:

  1. ModelAndView addObject(String attributeName, Object attributeValue)
    在这里插入图片描述2. void setViewName(String viewName)
    在这里插入图片描述示例代码:
/\*\*
\* 返回 ModeAndView
\*/
@RequestMapping("/testReturnModelAndView")
public ModelAndView testReturnModelAndView() {
	ModelAndView mv = new ModelAndView();
	mv.addObject("username", "张三");
	mv.setViewName("success");
	return mv;
}

响应的 jsp 代码:

<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
		<title>执行成功</title>
	</head>
	<body>
		执行成功!
		${requestScope.username}
	</body>
</html>

7.2 转发和重定向

在这里插入图片描述

7.2.1 forward 转发

controller 方法在提供了 String 类型的返回值之后,默认就是请求转发。我们也可以写成:

@RequestMapping("/testForward")
public String testForward() {
	System.out.println("AccountController 的 testForward 方法执行了。。。。");
	return "forward:/WEB-INF/pages/success.jsp";
}

需要注意的是,如果用了 formward:则路径必须写成实际视图 url,不能写逻辑视图
它相当于“request.getRequestDispatcher(“url”).forward(request,response)”。使用请求转发,既可以转发到 jsp,也可以转发到其他的控制器方法

7.2.2 Redirect 重定向

contrller 方法提供了一个 String 类型返回值之后,它需要在返回值里使用 redirect :

@RequestMapping("/testRedirect")
public String testRedirect() {
	System.out.println("AccountController 的 testRedirect 方法执行了。。。。");
	return "redirect:testReturnModelAndView";
}

它相当于“response.sendRedirect(url)”。需要注意的是,如果是重定向到 jsp 页面,则 jsp 页面不
能放在 WEB-INF 目录中
,否则无法找到。

7.2.3 ResponseBody 响应 json 数据
作用:

该注解用于将 Controller 的方法返回的对象,通过 HttpMessageConverter 接口转换为指定格式的数据,如:json,xml 等,通过 Response 响应给客户端。

使用示例:
  • 需求: 使用@ResponseBody 注解实现将 controller 方法返回对象转换为 json 响应给客户端。
  • 前置知识点: Springmvc 默认用 MappingJacksonHttpMessageConverter 对 json 数据进行转换,需要加入jackson 的包。
    在这里插入图片描述
    jsp 中的代码:
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery.min.js"></script>
<script type="text/javascript">
 $(function(){
 $("#testJson").click(function(){
 $.ajax({
 type:"post",
 url:"${pageContext.request.contextPath}/testResponseJson",
 contentType:"application/json;charset=utf-8",
 data:'{"id":1,"name":"test","money":999.0}',
 dataType:"json",
 success:function(data){
 alert(data);
 }
 });
 });
 })
</script>
<!-- 测试异步请求 -->
<input type="button" value="测试 ajax 请求 json 和响应 json" id="testJson"/>

控制器中的代码:

/\*\*
\* 响应 json 数据的控制器
\*/
@Controller("jsonController")
public class JsonController {
	/\*\*
 \* 测试响应 json 数据
 \*/
	@RequestMapping("/testResponseJson")
	public @ResponseBody Account testResponseJson(@RequestBody Account account) {
		System.out.println("异步请求:"+account);
		return account;
	}
}

运行结果:
在这里插入图片描述


八、SpringMVC 实现文件上传

8.1 文件上传的回顾

8.1.1 文件上传的必要前提:
  • form 表单的 enctype 取值必须是:multipart/form-data (默认值是:application/x-www-form-urlencoded)
    enctype:是表单请求正文的类型
  • method 属性取值必须是 Post
  • 提供一个文件选择域<input type=”file” />
8.1.2 文件上传的原理分析

当 form 表单的 enctype 取值不是默认值时,request.getParameter()将失效。

  • enctype=”application/x-www-form-urlencoded”时,form 表单的正文内容是:
    key=value&key=value&key=value
  • 当 form 表单的 enctype 取值为 Mutilpart/form-data 时,请求正文内容就变成 每一部分都是 MIME
    类型描述的正文:
-----------------------------7de1a433602ac                 分界符
Content-Disposition: form-data; name="userName"            协议头
aaa                                  					 协议的正文
-----------------------------7de1a433602ac
Content-Disposition: form-data; name="file"; 
filename="C:\Users\zhy\Desktop\fileupload_demofile\b.txt"
Content-Type: text/plain 							协议的类型(MIME 类型)
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
-----------------------------7de1a433602ac--

8.2 传统方式的文件上传

传统方式的文件上传,指的是我们上传的文件和访问的应用存在于同一台服务器上。并且上传完成之后,浏览器可能跳转。

第一步:引入依赖包
<dependency>
	<groupId>commons-fileupload</groupId>
	<artifactId>commons-fileupload</artifactId>
	<version>1.3.1</version>
</dependency>
<dependency>
	<groupId>commons-io</groupId>
	<artifactId>commons-io</artifactId>
	<version>2.4</version>
</dependency>

第二步:编写 jsp 页面
<form action="/fileUpload" method="post" enctype="multipart/form-data">
	名称:<input type="text" name="picname"/><br/>
	图片:<input type="file" name="uploadFile"/><br/>
	<input type="submit" value="上传"/>
</form>

第三步:编写控制器
@Controller("fileUploadController")
public class FileUploadController {
	@RequestMapping(value="/fileupload")
	public String fileupload(HttpServletRequest request) throws Exception {
		// 先获取到要上传的文件目录
		String path = request.getSession().getServletContext().getRealPath("/uploads");
		// 创建File对象,一会向该路径下上传文件
		File file = new File(path);
		// 判断路径是否存在,如果不存在,创建该路径
		if(!file.exists()) {
			file.mkdirs();
		}
		// 创建磁盘文件项工厂
		DiskFileItemFactory factory = new DiskFileItemFactory();
		ServletFileUpload fileUpload = new ServletFileUpload(factory);
		// 解析request对象
		List<FileItem> list = fileUpload.parseRequest(request);
		// 遍历
		for (FileItem fileItem : list) {
			// 判断文件项是普通字段,还是上传的文件
			if(fileItem.isFormField()) {
				//普通表单项
			}else {
				// 上传文件项
				// 获取到上传文件的名称
				String filename = fileItem.getName();
				//将文件名设置为唯一值,uuid
				String uuid = UUID.randomUUID().toString().replace("-", "");
				filename = uuid +"\_" + filename;
				// 上传文件
				fileItem.write(new File(file, filename));
				// 删除临时文件(上传文件大于10kb会在磁盘生成临时文件,需要手动处理,否则只会在内存生成临时文件,不需手动处理)
				fileItem.delete();
			}
		}
		return "success";
	}


8.3 springmvc 方式的文件上传

SpringMVC框架提供了MultipartFile对象,该对象表示上传的文件,要求变量名称必须和表单file标签的
name属性名称相同。
在这里插入图片描述

第一步:引入依赖包
<dependency>
	<groupId>commons-fileupload</groupId>
	<artifactId>commons-fileupload</artifactId>
	<version>1.3.1</version>
</dependency>
<dependency>
	<groupId>commons-io</groupId>
	<artifactId>commons-io</artifactId>
	<version>2.4</version>
</dependency>

第二步:编写 jsp 页面
<form action="/fileUpload" method="post" enctype="multipart/form-data">
	选择文件:<input type="file" name="upload"/><br/>
	<input type="submit" value="上传"/>
</form>

第三步:编写控制器
@Controller("fileUploadController")
public class FileUploadController {
	@RequestMapping("/fileUpload")
	public String uploadFile(MultipartFile upload, HttpServletRequest request) throws Exception{
		// 先获取到要上传的文件目录
		String path = request.getSession().getServletContext().getRealPath("/uploads");
		// 创建File对象,一会向该路径下上传文件
		File file = new File(path);
		// 判断路径是否存在,如果不存在,创建该路径
		if(!file.exists()) {
			file.mkdirs();
		}
		// 获取到上传文件的名称
		String filename = upload.getOriginalFilename();
		String uuid = UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
		// 把文件的名称唯一化
		filename = uuid + "\_" + filename;
		// 上传文件
		upload.transferTo(new File(file, filename));
		return "success";
	}
}

第四步:在springmvc.xml中配置文件解析器
<!-- 配置文件上传解析器 -->
<!-- id 的值是固定的-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
	<!-- 设置上传文件的最大尺寸为 5MB -->
	<property name="maxUploadSize">
		<value>5242880</value>
	</property>
</bean>

注意:
文件上传的解析器 id 是固定的,不能起别的名称,否则无法实现请求参数的绑定。(不光是文件,其他
字段也将无法绑定)


8.4 springmvc 跨服务器方式的文件上传

8.4.1 使用多服务器的目的

在实际开发中,我们会有很多处理不同功能的服务器。例如:

  • 应用服务器:负责部署我们的应用
  • 数据库服务器:运行我们的数据库
  • 缓存和消息服务器:负责处理大并发访问的缓存和消息
  • 文件服务器:负责存储用户上传文件的服务器。

(注意:此处说的不是服务器集群)
分服务器处理的目的是让服务器各司其职,从而提高我们项目的运行效率。
在这里插入图片描述

8.4.2 跨服务器文件上传的实现

在这里插入图片描述

第一步:在IDEA中配置两个 tomcat 服务器,端口号不能相同
第二步:创建两个web项目,分别部署到前面配置的服务器中

假设第一个web项目叫“myAPP”,用于上传文件;第二个web项目叫“fileServer”,用于存放文件。
在fileServer项目的webapp目录下新建一个文件夹"uploads"用于存放文件。

第三步:配置myAPP项目
  1. 导入开发需要的jar包
<dependency>
	<groupId>com.sun.jersey</groupId>
	<artifactId>jersey-core</artifactId>
	<version>1.18.1</version>
</dependency>
<dependency>
	<groupId>com.sun.jersey</groupId>
	<artifactId>jersey-client</artifactId>
	<version>1.18.1</version>
</dependency>

  1. 编写文件上传的JSP页面
<h3>跨服务器的文件上传</h3>
<form action="user/fileupload" method="post" enctype="multipart/form-data">
	选择文件:<input type="file" name="upload"/><br/>
	<input type="submit" value="上传文件"/>
</form>

  1. 编写控制器
@RequestMapping(value="/user")
public class FileUploadController {
	@RequestMapping(value="/fileupload")
	public String fileupload3(MultipartFile upload) throws Exception {
		System.out.println("SpringMVC跨服务器方式的文件上传...");
		// 定义图片服务器的请求路径
		String path = "http://localhost:9090/uploads/";
		// 获取到上传文件的名称
		String filename = upload.getOriginalFilename();
		String uuid = UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
		// 把文件的名称唯一化
		filename = uuid+"\_"+filename;
		// 向图片服务器上传文件
		// 创建客户端对象
		Client client = Client.create();
		// 连接图片服务器
		WebResource webResource = client.resource(path+filename);
		// 上传文件
		webResource.put(upload.getBytes());
		return "success";
	}
}


九、SpringMVC 中的异常处理

9.1 异常处理的思路

系统中异常包括两类:预期异常和运行时异常 RuntimeException,前者通过捕获异常从而获取异常信息,
后者主要通过规范代码开发、测试通过手段减少运行时异常的发生。
项目的 dao、service、controller 出现异常都通过 throws Exception 向上抛出,最后由 springmvc 前端
控制器有DispatcherServlet交由异常处理器进行异常处理,如下图:在这里插入图片描述

9.2 实现步骤

第一步:自定义异常类
public class CustomException extends Exception {
	private String message;
	public CustomException(String message) {
		this.message = message;
	}
	public String getMessage() {
		return message;
	}
}

第二步:编写错误页面

error.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
		<title>执行失败</title>
	</head>
	<body>
		执行失败!
		${message }
	</body>
</html>

第三步:自定义异常处理器
public class CustomExceptionResolver implements HandlerExceptionResolver {
	@Override
	public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
		ex.printStackTrace();
		CustomException customException = null;
		//如果抛出的是自定义异常则直接转换
		if(ex instanceof CustomException){
		customException = (CustomException)ex;
		}else{
		//如果抛出的不是自定义异常则重新构造一个系统错误异常。
		customException = new CustomException("系统错误,请与系统管理 员联系!");
		}
		ModelAndView modelAndView = new ModelAndView();
		modelAndView.addObject("message", customException.getMessage());
		modelAndView.setViewName("error");
		return modelAndView;
	}
}

第四步:配置异常处理器

springmvc.xml 文件中配置:

<!-- 配置自定义异常处理器 -->
<bean id="handlerExceptionResolver" class="com.itheima.exception.CustomExceptionResolver"/>


十、 SpringMVC 中的拦截器

10.1 拦截器的作用

  • Spring MVC 的处理器拦截器类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理后处理
  • 用户可以自己定义一些拦截器来实现特定的功能。
  • 拦截器链(Interceptor Chain):拦截器链就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。
  • 拦截器和过滤器是有几分相似,但是也有区别:
    1. 过滤器是 servlet 规范中的一部分,任何 java web 工程都可以使用。拦截器是 SpringMVC 框架自己的,只有使用了 SpringMVC 框架的工程才能用。
    2. 过滤器在 url-pattern 中配置了/*之后,可以对所有要访问的资源拦截。拦截器只会拦截访问的控制器方法,如果访问的是 jsp,html,css,image 或者 js 是不会进行拦截的。

拦截器是 AOP 思想的具体应用。我们要想自定义拦截器, 要求必须实现 HandlerInterceptor 接口

10.2 自定义拦截器步骤

10.2.1 第一步:创建类,实现HandlerInterceptor接口
public class HandlerInterceptorDemo1 implements HandlerInterceptor {
	/\*\*
 \* controller方法执行前,进行拦截的方法
 \* return true放行
 \* return false拦截
 \* 可以使用转发或者重定向直接跳转到指定的页面。
 \*/
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
		System.out.println("preHandle 拦截器拦截了");
		return true;
	}
	
	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
		System.out.println("postHandle 方法执行了");
	}
	
	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse	response, Object handler, Exception ex)	throws Exception {
		System.out.println("afterCompletion 方法执行了");
	}
}

10.2.2 第二步:在springmvc.xml中配置拦截器类
<!-- 配置拦截器 -->
<mvc:interceptors>
	<mvc:interceptor>
		<!-- 哪些方法进行拦截 -->
		<mvc:mapping path="/\*\*"/>
		<!-- 哪些方法不进行拦截
 <mvc:exclude-mapping path=""/>
 -->
		<!-- 注册拦截器对象 -->
		<bean id="handlerInterceptorDemo1" class="web.interceptor.HandlerInterceptorDemo1"></bean>
	</mvc:interceptor>
</mvc:interceptors>

10.3 拦截器执行细节

HandlerInterceptor接口中的方法:

preHandle方法:

  1. controller方法执行前调用
  2. 可以使用request或者response跳转到指定的页面
  3. return true放行,执行下一个拦截器;如果没有拦截器,则执行controller中的方法。
  4. return false不放行,不会执行controller中的方法。

postHandle方法:

  1. controller方法执行后执行的方法,在JSP视图执行前。
  2. 可以使用request或者response跳转到指定的页面
  3. 如果指定了跳转的页面,那么controller方法跳转的页面将不会显示。

afterCompletion方法:

  1. 只有 preHandle 返回 true 才调用,是在JSP执行后执行
  2. request或者response不能再跳转页面了
  3. 可以在该方法中进行一些资源清理的操作

如果有2个拦截器,拦截器 1 的 preHandle 方法返回 true,但是拦截器 2 的 preHandle 方法返
回 false,此时的执行顺序为:
preHandle 1 ----> preHandle 2 -----> afterCompletion 1

10.4 多个拦截器的执行顺序

在这里插入图片描述
在这里插入图片描述
配置多个拦截器的方法

<!-- 配置拦截器 -->
<mvc:interceptors>
	<mvc:interceptor>
		<!-- 哪些方法进行拦截 -->
		<mvc:mapping path="/user/\*"/>
		<!-- 哪些方法不进行拦截
 <mvc:exclude-mapping path=""/>
 -->
		<!-- 注册拦截器对象 -->
		<bean class="demo.MyInterceptor1"/>
	</mvc:interceptor>
	<mvc:interceptor>
		<!-- 哪些方法进行拦截 -->
		<mvc:mapping path="/\*\*"/>
		<!-- 注册拦截器对象 -->
		<bean class="demo.MyInterceptor2"/>
	</mvc:interceptor>
</mvc:interceptors>

10.5 拦截器的简单案例(验证用户是否登录)

实现思路

1、有一个登录页面,需要写一个 controller 访问页面
2、登录页面有一提交表单的动作,需要在 controller 中处理。

  • 2.1、判断用户名密码是否正确
  • 2.2、如果正确 向 session 中写入用户信息
  • 2.3、返回登录成功。

3、拦截用户请求,判断用户是否登录

  • 3.1、如果用户已经登录,放行
  • 3.2、如果用户未登录,跳转到登录页面
控制器代码
//登录页面
@RequestMapping("/login")
public String login(Model model)throws Exception{
	return "login";
}

//登录提交
//userid:用户账号,pwd:密码
@RequestMapping("/loginsubmit")
public String loginsubmit(HttpSession session,String userid,String pwd) throws Exception{
	//向 session 记录用户身份信息
	session.setAttribute("activeUser", userid);
	return "redirect:/main.jsp";
}

//退出
@RequestMapping("/logout")
public String logout(HttpSession session)throws Exception{
	//session 过期
	session.invalidate();
	return "redirect:index.jsp";
}

拦截器代码
public class LoginInterceptor implements HandlerInterceptor{
	@Override
	Public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
		//如果是登录页面则放行
		if(request.getRequestURI().indexOf("login.action")>=0){
			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;
	}
}

最后

2020年在匆匆忙忙慌慌乱乱中就这么度过了,我们迎来了新一年,互联网的发展如此之快,技术日新月异,更新迭代成为了这个时代的代名词,坚持下来的技术体系会越来越健壮,JVM作为如今是跳槽大厂必备的技能,如果你还没掌握,更别提之后更新的新技术了。

更多JVM面试整理:

、返回登录成功。

3、拦截用户请求,判断用户是否登录

  • 3.1、如果用户已经登录,放行
  • 3.2、如果用户未登录,跳转到登录页面
控制器代码
//登录页面
@RequestMapping("/login")
public String login(Model model)throws Exception{
	return "login";
}

//登录提交
//userid:用户账号,pwd:密码
@RequestMapping("/loginsubmit")
public String loginsubmit(HttpSession session,String userid,String pwd) throws Exception{
	//向 session 记录用户身份信息
	session.setAttribute("activeUser", userid);
	return "redirect:/main.jsp";
}

//退出
@RequestMapping("/logout")
public String logout(HttpSession session)throws Exception{
	//session 过期
	session.invalidate();
	return "redirect:index.jsp";
}

拦截器代码
public class LoginInterceptor implements HandlerInterceptor{
	@Override
	Public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
		//如果是登录页面则放行
		if(request.getRequestURI().indexOf("login.action")>=0){
			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;
	}
}

最后

2020年在匆匆忙忙慌慌乱乱中就这么度过了,我们迎来了新一年,互联网的发展如此之快,技术日新月异,更新迭代成为了这个时代的代名词,坚持下来的技术体系会越来越健壮,JVM作为如今是跳槽大厂必备的技能,如果你还没掌握,更别提之后更新的新技术了。

[外链图片转存中…(img-0xJ9mWgJ-1714471013020)]

更多JVM面试整理:

[外链图片转存中…(img-E28Uxx7W-1714471013021)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

  • 12
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值