SpringMVC学习3 - JavaWeb - 参数校验、文件上传、异常统一处理、JSON与Bean对象之间的相互转换、Restful请求编写方式

1. 参数校验 - 使用hiebernate的校验包

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ovXTVFhx-1587882402640)(en-resource://database/14958:1)]

需要的jar包
classmate.jar
hibernate-validator.jar
jboss-logging.jar
validation-api

1.1 常用注解

图片来自其他博客:https://blog.csdn.net/dh554112075/article/details/80790464
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JT5YfJID-1587882402658)(en-resource://database/14968:1)]

1.2 小案例

  

注解的作用
@ModelAttribute('属性名'):其实就是Model.setAttribute('参数名', object)
修饰形参
修饰有返回值的方法
@Validated:使一个对象内的属性验证注解生效


1. springMVC.xml的配置

<!--使有关SpringMVC的注解生效  ~  配置校验参数的注解使用哪一个Class进行解析      --> 
<mvc:annotation-driven validator="localValidatorFactoryBean" ></mvc:annotation-driven>

<!-- 声明需要使用到的校验器 - 交给容器管理 -->
<bean id="localValidatorFactoryBean" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
    <property name="ProviderClass" value="org.hibernate.validator.HibernateValidator" ></property>
</bean>


2. add.jsp - 表单添加页面

<form action="${pageContext.request.contextPath}/users/addUI" method="post">
    name:<input type="text" name="name">
    <br/>
    age:<input type="text" name="age">
    <br/>
    id:<input type="text" name="id">
    <br/>
    password:<input type="text" name="password">
    <br/>
    <input type="submit"  value="添加">
</form>


3. User.java – javaBean对象

public class User {
    
    	
	String name;
	Integer age;
	
	// 账号密码不能为空 - 利用注解自行校验
	@NotBlank
	String id;
	@NotBlank
	String password;
}


4. UserServlet - 请求处理页面

@Controller
@RequestMapping("/users/")
public class UserServlet {
    
    

	// 映射的地址应该是:  /users/addUI
	@RequestMapping(value="/addUI")
	public String add() {
    
    
		return "user/add";
	}
	
	@RequestMapping(value="/addUI", method=RequestMethod.POST)
	public ModelAndView add2(@ModelAttribute(value="myUser") @Validated User user, Errors errors) {
    
    
		
		ModelAndView mav = new ModelAndView();		
		if(errors.hasErrors()) {
    
    			
			List<FieldError> fieldErrors = errors.getFieldErrors();			
			for(FieldError fe : fieldErrors) {
    
    
				System.out.println(fe.getField() + ":" + fe.getDefaultMessage());
			}		
			mav.setViewName("user/add");
			return mav;
		}				
		mav.setViewName("redirect:/users/list");
		return mav;		
	}
    
}


  运行效果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-t3b3UFFV-1587882402684)(en-resource://database/14964:1)]

如果不填id、password两个选项,则直接后面报有信息
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VuHT1emH-1587882402688)(en-resource://database/14966:1)]

2. 文件上传

2.1 单文件上传

步骤:

  1. 导入JAR包
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kKb8XR6p-1587882402695)(en-resource://database/14970:1)]

  2. 配置springMVC - CommonsMultipartResolver


小案例

  1. springMVC.xml的配置

<!--注意这里的ID名不可以省略,我也不知道为什么。一省略就出错-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
		<property name="maxUploadSize" value="400000"></property>
</bean>


  2. uploadTest.jsp – 前端页面

<body>
	<form action="${pageContext.request.contextPath}/pages/upload"
		method="post" enctype="multipart/form-data">
		<input type="file" name="uploadFile"><br/>
		<input type="submit" value="上传">
	</form>

	<div>
		<h2>上传了文件:</h2>
		<h5>
			<c:choose>
				<c:when test="${ not empty fileMessage.fileName}">
					文件名:${fileMessage.fileName} <br/>
					文件类型:${fileMessage.contentType} <br/>
					文件大小${fileMessage.size } <br/>
					请求参数名:${fileMessage.fileParamName}
				</c:when>	
				<c:otherwise>
					当前无文件上传
				</c:otherwise>
			</c:choose>
		</h5>
	</div>

</body>


  3. FileMessage.java - 保存上传文件信息的Bean对象

public class FileMessage {
    
    	
	Object fileName;
	Object contentType;
	Object fileParamName;
	Object size;
}


  4. pageServelt.java - 请求处理控制器

@Controller
@RequestMapping(value = "pages")
public class PageServlet {
    
    
	
	// 用来进行跳转到文件上传页面
	@RequestMapping(value="upload", method= {
    
    RequestMethod.GET})
	public String upload() {
    
    
		return "/page/uploadTest";
	}
	
	// 处理前端页面传过来的文件
	@RequestMapping(value="upload", method= {
    
    RequestMethod.POST})
	public String upload(MultipartFile uploadFile, HttpSession session) {
    
    
		
		// 获取文件的信息
		Object contentType = uploadFile.getContentType();
		Object fileName = uploadFile.getOriginalFilename();
		Object size = uploadFile.getSize();
		Object fileParamName = uploadFile.getName();
		
		// 将文件的信息传入到fileMessage的Bean对象
		top.linruchang.domain.FileMessage fm = new top.linruchang.domain.FileMessage();
		fm.setContentType(contentType);
		fm.setFileName(fileName);
		fm.setFileParamName(fileParamName);
		fm.setSize(size);
		session.setAttribute("fileMessage", fm);
		
		// 将上传的文件复制到桌面
		try {
    
    
			uploadFile.transferTo(new File("E:\\测试\\" + fileName));
		} catch (IllegalStateException | IOException e) {
    
    
			e.printStackTrace();
		}
		
		// 重定向到文件上传页面
		return "redirect:/pages/upload";
	}
	
}


  运行效果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qKXonwVm-1587882402699)(en-resource://database/14972:1)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-thcif3yl-1587882402705)(en-resource://database/14974:1)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-76mEhkoi-1587882402710)(en-resource://database/14976:1)]

2.2 多文件上传

1. 跟上面的代码差不多

2. 注意的是:形参上必须写@RequestParam(“input的name名”),即使形参跟name一样也需要写,否则报错

// 处理前端多文件上传页面传过来的文件 - 切记形参上必须写@RequestParam("")
@RequestMapping(value="uploads", method= {
    
    RequestMethod.POST})
public String uploads(@RequestParam("uploadFiles") MultipartFile[] uploadFiles) {
    
    

    if(uploadFiles == null) {
    
    
        System.out.println("上传的文件没有接收到");
    }

    for(MultipartFile mf : uploadFiles) {
    
    
        Object fileName = mf.getOriginalFilename();
        try {
    
    
            mf.transferTo(new File("E:\\测试\\" + fileName));
        } catch (IllegalStateException | IOException e) {
    
    
            e.printStackTrace();
        }
        System.out.println("上传成功" + fileName);
    }

    // 重定向到文件上传页面
    return "redirect:/pages/uploads";
}

3. 异常处理

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-clpBZBtk-1587882402716)(en-resource://database/14978:1)]

3.1 使用步骤

1. 自定义异常
2. 自定义全局异常处理器 - 跳转到异常页面
3. 异常处理器交给springMVC.xml进行管理

3.2 简单使用 - 案例

1. 自定义异常

public class CustomException extends RuntimeException {
    
    

	private static final long serialVersionUID = 1L;

	public CustomException() {
    
    
		super();
		
	}

	public CustomException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
    
    
		super(message, cause, enableSuppression, writableStackTrace);
		
	}

	public CustomException(String message, Throwable cause) {
    
    
		super(message, cause);
		
	}

	public CustomException(String message) {
    
    
		super(message);
		
	}

	public CustomException(Throwable cause) {
    
    
		super(cause);
		
	}

}

2. 自定义异常处理器

public class MyExceptionHandler implements HandlerExceptionResolver{
    
    
	@Override
	public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
			Exception ex) {
    
    
		ModelAndView mav = new ModelAndView();
		if( ex instanceof CustomException) {
    
    
			
			mav.setViewName("/exception/customException");
			return mav;
		}
		return null;
	}

}

3. springMVC.xml – 自定义异常处理器交给容器管理

 <bean class="top.linruchang.exception.MyExceptionHandler"></bean>

4. 异常发生时的页面

<body>
     <h1 style="color:red">请求执行时发生自定义异常</h1>
</body>

5. 自己模仿抛出一个异常出来
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PU4RJvJ2-1587882402722)(en-resource://database/14982:1)]


  运行效果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PBhlGUK4-1587882402728)(en-resource://database/14984:1)]

4. JSON-Java对象之间的转换

4.1 使用步骤

使用步骤

  1. 导入JAR包
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gQbwEXTf-1587882402738)(en-resource://database/14986:1)]

  2. 使用注解进行修饰JSON数据、Java对象的转换
    @ReuqestBody:修饰形参对象-JSON数据转为Java对象
    @ResponseBody:修饰具有返回值的方法 - 将Java对象转为JSON数据字符串

4.2 小案例

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yyfs4G63-1587882402743)(en-resource://database/14988:1)]

1. JSONTest.jsp – 前端页面

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src='${pageContext.request.contextPath}/static/js/jquery-3.4.1.min.js' type='text/javascript'></script>
</head>
<body>
	<button id="btn">发送json数据,并且返回json数据</button>
</body>
<script>
	$(function() {
     
     
		$("#btn").click(function() {
     
     
			$.ajax({
     
     
				type:"post",
				url:"${pageContext.request.contextPath}/pages/JSONTest",
				data: '{"name":"lrc", "age":18, "id":"lrcnb", "password":"123456"}',
				contentType:"application/json;charset=utf-8",
				success:function(data) {
     
     
					console.log(data);
				}
			})			
			
		})
	})
</script>
</html>



2. pageServlet.java - 控制器

@Controller
@RequestMapping(value = "pages")
public class PageServlet {
    
    
   
   // 将请求跳转到JSONTest测试页面
   @RequestMapping(value="JSONTest", method= {
    
    RequestMethod.GET})
   public String JSONTest() {
    
    
   	return "/page/JSONTest";
   }
   
   //JSON的转换 -- 处理AJAX请求
   @RequestMapping(value="JSONTest", method= {
    
    RequestMethod.POST})
   @ResponseBody  //将返回的Java对象转为Json数据字符串
   public User JSONTest(@RequestBody User user) {
    
    
   	//json数据转为Java对象
   	System.out.println("json转为User对象:" + user);
   	return user;
   }
   
}


  运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jmlT4EZS-1587882402747)(en-resource://database/14990:1)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vjKg5hmC-1587882402763)(en-resource://database/14992:1)]

5. Restful - 请求地址编写风格

5.1 概念

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3J5KBO8y-1587882402770)(en-resource://database/14994:1)]

Restful特点
资源的从属关系:例子
所有动物园:/zoos
某个动物园:/zoos/n
某个动物园所有动物:/zoos/n/animals
某个动物园的某个动物:/zoos/n/animals/m
不同请求方法代表不同操作
get:获取数据
post:添加数据行
put:更新数据
delete:删除数据行

一般我们更新都需要表单,然而只支持GET、POST两种请求方式,想要达成Restful风格要求,则需要隐藏表单值是请求方式、以及SPringMVC内置的过滤器进行更改对应的请求 - 当然也可以自己写过滤器更改请求方法

AJAX能发送多种请求方式

5.2 小案例

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zsJp785A-1587882402776)(en-resource://database/14996:1)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Izhcr0Cy-1587882402781)(en-resource://database/14998:1)]


1. web.xml - 请求转换过滤器配置

<filter>
    <filter-name>hiddenHttpMethodFilter</filter-name>
    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>hiddenHttpMethodFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>


2. list.jsp - 数据显示页面

<body>
	<table border="1">
		<thead>
			<tr>
				<th>姓名</th>
				<th>年龄</th>
				<th>操作</th>
			</tr>
		</thead>
		<tbody>
			<c:forEach items="${requestScope.users}" var="user">
				<tr>
					<td>${user.name}</td>
					<td>${user.age}</td>
					<td>
						<a href="${pageContext.request.contextPath}/users/updateUI?name=${user.name}&age=${user.age}">修改</a>
						<a href="${pageContext.request.contextPath}/users/deleteUI?name=${user.name}&age=${user.age}">删除</a>
					</td>
				</tr>	
			</c:forEach>
		</tbody>
	</table>
	<br/><br/>
	<a href="${pageContext.request.contextPath}/users/addUI">添加记录</a>
</body>


3. update.jsp - 数据更新页面

<body>
	<form action="${pageContext.request.contextPath}/users/updateUI" method="post">
		<input type="hidden" name="_method" value="put">
		<input type="text" name="name" readonly="readonly" value="${requestScope.user.name}">
		<input type="text" name="age" value="${requestScope.user.age}">
		<input type="submit"  >
	</form>
</body>


4. UserServlet - 请求处理器

@Controller
@RequestMapping("/users/")
public class UserServlet {
    
    
	
	// 保存用户的信息 -- 只是模拟,数据应该从数据库中取
	static  List<User>  users = new ArrayList<User>();
	static {
    
    
		User user = new User();
		user.setName("lrc");
		user.setAge(25);
		users.add(user);
	}
	
	// 默认处理 get请求 -- 处理其他的请求方式需要自己手动定义
	// 映射的地址应该是:  /users/list 
	// 客户真正的请求地址等于处理类上的@RequestMapping地址+方法类上的@RequestMapping上的注解
	@RequestMapping("list")
	public ModelAndView list() {
    
    
		ModelAndView mav = new ModelAndView();
		mav.addObject("users", users);
		
		 // 视图名 - 需要交给springmvc.XML配置的的InternalResourceViewResolver进行转换成真正的地址
		mav.setViewName("user/list");   
		return mav;
	}
		
	@RequestMapping(value="/updateUI")
	public ModelAndView update(User user) {
    
    
		
		ModelAndView mav = new ModelAndView();
		mav.addObject("user", user);
		mav.setViewName("user/update");
		return mav;
	}
	
	@RequestMapping(value="/updateUI", method=RequestMethod.PUT)
	public ModelAndView update2(User user, HttpServletRequest req) {
    
    
		System.out.println(req.getMethod());
		System.out.println(user);
		for(User user1 : users) {
    
    
			if(user1.getName().equals(user.getName())) {
    
    
				user1.setAge(user.getAge());
				break;
			}
		}
		ModelAndView mav = new ModelAndView();
		mav.setViewName("redirect:/users/list");
		return mav;
	}	
			
}


  运行效果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N4yYEt4n-1587882402791)(en-resource://database/15000:1)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CU7bkJ7P-1587882402795)(en-resource://database/15004:1)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HiccX3CS-1587882402807)(en-resource://database/15006:1)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VAfBp4Rv-1587882402814)(en-resource://database/15008:1)]

猜你喜欢

转载自blog.csdn.net/weixin_39651356/article/details/105768421