1.Controller接收客户端传的参数
1)参数是基本数据类型/包装类型/String
@RequestMapping("test")
public String test(int age){...}
public String test(long id){...}
public String test(boolean flag){...}
public String test(Long id){...}
public String test(String name){...}
注意参数名字要和客户端传的参数名一致,否则需要使用@RequestParam来指定参数名
2)参数是数组类型
@RequestMapping("test")
public String test(int[] age){...}
public String test(long[] id){...}
public String test(boolean[] flag){...}
public String test(Long[] id){...}
public String test(String[] name){...}
注意客户端传值类似于这样:
name=tom&name=lisi
注意客户端传值还可以使用json的方式
@RequestMapping("/index")
@ResponseBody
public String index(@RequestBody String[] arr){...}
$("#btn").on("click",function(){
var arr = [];
arr.push("hello");
arr.push("world");
$.ajax({
type:"post",
url:"test/index",
contentType:"application/json", //发送数据的数据类型.
data:JSON.stringify(arr), //发送的数据
dataType:"json", //接收的返回数据的类型
success:function(data){
console.log("data = "+data);
}
});
});
3)参数是类类型(例如实体类Uesr、Student等)
@RequestMapping("test")
public String test(User user){...}
注意客户端传值类似于这样:
username=tom&password=123&dob=2017-10-21
注意:
1.username/password/dob必须是User中存在的property
2.日期类型的转换
4)参数是类类型的数组
例如:
@RequestMapping("/test")
public String test(@RequestBody User[] users){...}
$("#btn").on("click",function(){
var arr = [];
var json1 = {username:"tom",password:"123",dob:"1999-10-27"};
var json2 = {username:"zss",password:"456",dob:"2000-10-27"};
arr.push(json1);
arr.push(json2);
$.ajax({
type:"post",
url:"/test",
contentType:"application/json",
data:JSON.stringify(arr),
dataType:"json",
success:function(data){
console.log("data = "+data);
}
});
});
5)List/Set集合
例如1:如果是set集合,直接把List换成Set即可,其他不用改
@RequestMapping("/index")
@ResponseBody
public String index(@RequestBody List<String> list){...}
$("#btn").on("click",function(){
var arr = [];
arr.push("hello");
arr.push("world");
$.ajax({
type:"post",
url:"test/index",
contentType:"application/json",
data:JSON.stringify(arr),
dataType:"json",
success:function(data){
console.log("data = "+data);
}
});
});
例如2:如果是set集合,直接把List换成Set即可,其他不用改
@RequestMapping("/index")
@ResponseBody
public String index(@RequestBody List<User> list){....}
$("#btn").on("click",function(){
var arr = [];
var json1 = {username:"tom",password:"123",dob:"1999-10-27"};
var json2 = {username:"zss",password:"456",dob:"2000-10-27"};
arr.push(json1);
arr.push(json2);
$.ajax({
type:"post",
url:"test/index",
contentType:"application/json",
data:JSON.stringify(arr),
dataType:"json",
success:function(data){
console.log("data = "+data);
}
});
});
6)Map集合
例如:
@RequestMapping("/index")
@ResponseBody
public String index(@RequestBody Map<String,User> map){...}
$("#btn").on("click",function(){
var map = {};
var json1 = {username:"tom",password:"123",dob:"1999-10-27"};
var json2 = {username:"zss",password:"456",dob:"2000-10-27"};
map[json1.username] = json1;
map[json2.username] = json2;
$.ajax({
type:"post",
url:"test/index",
contentType:"application/json",
data:JSON.stringify(map),
dataType:"json",
success:function(data){
console.log("data = "+data);
}
});
});
7)以上任何类型遇到特殊情况下,都可以使用自定义类型转换器:
spring提供的转换器接口:
public interface Converter<S, T> {
T convert(S source);
}
可以让我们把任意类型S转换为T类型,但是转换的代码需要我们来提供给spring
编写完成后需要在spring中注册,例如:
<mvc:annotation-driven conversion-service="formatService"/>
<bean name="formatService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>
<!-- 自己编写的类型转换器,可以有多个 -->
<bean class="com.briup.web.converter.StringToDateConverter"></bean>
</set>
</property>
</bean>
2.SpringMVC中的跳转
1.因为在Controller中的功能处理方法上可以获得到request和response,所以可以像之前servlet中一样,进行服务器内部跳转和客户端重定向
例如:
@Controller
@RequestMapping("/dispatcher")
public class DispatcherController {
@RequestMapping("/b")
public String testB(){
System.out.println("testB");
return "index";
}
@RequestMapping("/c")
public String testC(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException{
System.out.println("testC");
//服务器内部跳转到一个页面
//request.getRequestDispatcher("/WEB-INF/jsp/index.jsp").forward(request, response);
//服务器内部跳转到一个功能处理方法
//request.getRequestDispatcher("/dispatcher/b").forward(request, response);
//客户端重定向到另一个功能处理方法
response.sendRedirect(request.getContextPath()+"/dispatcher/b");
return null;
}
}
2.Controller中可以使用字符串表示服务器内部跳转和客户端重定向
例如:
@Controller
@RequestMapping("/dispatcher")
public class DispatcherController {
@RequestMapping("/a")
public String testA(){
System.out.println("testA");
//服务器内部跳转到另一个功能处理方法
//return "forward:/dispatcher/b";
//客户端重定向到另一个功能处理方法
//return "redirect:/dispatcher/b";
//服务器内部跳转到一个页面
return "index";
}
@RequestMapping("/b")
public String testB(){
System.out.println("testB");
return "index";
}
}
3.Controller中使用ModelAndView进行跳转和重定向
@Controller
@RequestMapping("/dispatcher")
public class DispatcherController {
@RequestMapping("/b")
public String testB(){
System.out.println("testB");
return "index";
}
@RequestMapping("/d")
public ModelAndView testD() throws ServletException, IOException{
System.out.println("testD");
//服务器内部跳转到另一个功能处理方法
//ModelAndView mv = new ModelAndView("forward:/dispatcher/b");
//客户端重定向到另一个功能处理方法
//ModelAndView mv = new ModelAndView("redirect:/dispatcher/b");
//服务器内部跳转到一个页面
ModelAndView mv = new ModelAndView("index");
return mv;
}
}
3.SpringMVC中的数据验证
通常在项目中使用较多的是前端校验,比如页面中js校验。对于安全要求较高的建议在服务端同时校验
SpringMVC使用hibernate的实现的校验框架validation,所以需要导入相关依赖的jar包
classmate-1.1.0.jar
hibernate-validator-5.1.3.Final.jar
jboss-logging-3.1.4.GA.jar
validation-api-1.1.0.Final.jar
数据校验之后,如果有错误信息,那么需要使用spring提供的标签库中的标签在页面中显示校验信息
<%@taglib prefix="sf" uri="http://www.springframework.org/tags/form" %>
例如:
valid.jsp页面主要代码:
<sf:form method="post" modelAttribute="user">
<sf:label path="name">用户名:</sf:label>
<sf:input path="name"/>
<sf:errors path="name" cssStyle="color:red"></sf:errors><br>
<sf:label path="age"> 年 龄:</sf:label>
<sf:input path="age"/>
<sf:errors path="age" cssStyle="color:red"></sf:errors><br>
<sf:label path="dob"> 生 日:</sf:label>
<sf:input path="dob"/>
<sf:errors path="dob" cssStyle="color:red"></sf:errors><br>
<input type="submit" value="提交"/>
</sf:form>
注意:
1.需要访问一个Controller再跳转到这个页面,同时需要向模型中添加一个名字叫user的对象(这就是之前说的命令/表单对象),否则跳转到这个页面的时候会报错
2.表单中没有这种action属性值,那么默认把数据提交给当前页面,但是提交方式是post
3.input标签中的path属性的值对应的是表单对象中的属性
4.Controller中映射的url为:/Valid/add , 如果是get方式访问这个url那么就把valid.jsp显示给用户,如果是post方式访问这个url,就表示要提交表单的数据。
5.在Controller中,在需要验证的参数前面加入@Valid注解
6.方法参数列表中,加入BindingResult对象,用来接收验证的错误信息,并根据这个进行不同情况的跳转
7.在被验证的表单对象所属类中,给需要验证的属性上加入指定注解
Controller中代码:
@Controller
@RequestMapping("/valid")
public class ValidController {
@RequestMapping(value="/add", method = {RequestMethod.GET})
public String showAddPage(Model model){
if(!model.containsAttribute("teacher")){
model.addAttribute("teacher", new Teacher());
}
return "valid";
}
@RequestMapping(value="/add",method = {RequestMethod.POST})
public String addTeacher(@Valid Teacher teacher,BindingResult bindingResult){
//如果验证数据中有错误信息,将保存在bindingResult对象中
if(bindingResult.hasErrors()){
List<ObjectError> errorList = bindingResult.getAllErrors();
for(ObjectError error : errorList){
System.out.println(error.getDefaultMessage());
}
//验证不通过在跳到valid页面,因为页面上有显示错误的标签
return "valid";
}
//没有错误则跳到test页面
return "test";
}
}
User类中代码:
public class User {
private long id;
@Size(min=5,max=8)
private String name;
private Integer age;
private Date dob;
get/set
}
常用的数据校验的注解
@Null 值只能为null
@NotNull 值不能为null
@NotEmpty 值不为null且不为空
@NotBlank 值不为null且不为空(先去除首尾空格)
@Pattern 正则表达式验证
@Size 限制长度在x和y之间
@Max 最大值
@Min 最小值
@Future 必须是一个将来的日期(和现在比)
@Past 必须是一个过去的日期(和现在比)
@Email 校验email格式
注意:日期属性上要加@DateTimeFormat(pattern="yyyy-MM-dd"),否则页面传的字符串是不能自动转为为日期的
4.SpringMVC中的异常处理
在SpringMVC中可以把异常统一进行处理,只需加入以下配置:
<!-- Spring提供的默认的异常解析器,也可以自定义 -->
<!-- 可以在jsp目录下新建一个error目录,然后放入显示错误页面 -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<!-- 定义默认的异常处理页面,当该异常类型的注册时使用 -->
<!-- value="error" 表示跳转的逻辑视图名字 -->
<property name="defaultErrorView" value="error/error"></property>
<!-- 定义异常处理页面用来获取异常信息的变量名,默认名为exception -->
<property name="exceptionAttribute" value="ex"></property>
<!-- 定义需要特殊处理的异常,用简单类名或全限定名作为key,异常页名的逻辑视图名作为value -->
<property name="exceptionMappings">
<props>
<prop key="IOException">error/error_io</prop>
<prop key="java.sql.SQLException">error/error_sql</prop>
</props>
</property>
</bean>
Controller中代码:
@RequestMapping("/test")
public String test()throws Exception{
//int a = 1/0;
//System.out.println(a);
int a = 1;
if(a==1){
throw new IOException("不好了,出错了!");
}
return "test";
}
页面中:
1.如果使用jsp的脚本显示信息
<!-- 因为spring中修改了异常的默认名字,所以这里是ex -->
<% Exception ex = (Exception)request.getAttribute("ex"); %>
<H2>Exception: <%= ex.getMessage()%></H2>
<P/>
<% ex.printStackTrace(new java.io.PrintWriter(out)); %>
2.如果是EL显示错误信息
<div>${ex }</div>
<div>${ex.message }</div>
异常处理也可以使用注解的形式,注意这个@ExceptionHandler是要加在需要异常处理的Controller中(推荐使用上面的那种配置方式)
@Controller
public class XxxxController {
@RequestMapping("/test")
public String test()throws Exception{
// int a = 1/0;
// System.out.println(a);
int a = 1;
if(a==1){
throw new IOException("你说呢?");
}
return "test";
}
@ExceptionHandler(value={IOException.class,SQLException.class})
public String exp(Exception ex,HttpServletRequest request) {
request.setAttribute("ex", ex);
return "error_io";
}
}
5.SpringMVC中上传
使用上传功能需要引入俩个jar包:
commons-fileupload-1.2.2.jar
commons-io-2.0.1.jar
利用spring中提供的MultipartFile接口实现上传功能
MultipartFile中几个重要的方法:
getName : 获取表单中文件组件的名字(上传框的名字)
getOriginalFilename : 获取上传文件的原名(上传文件名字)
transferTo(File newFile);把上传的文件转存到指定文件中(把上传的文件写入到一个指定的位置)
spring配置文件中加入以下配置:
<!-- SpringMVC上传文件时,需要配置MultipartResolver处理器 -->
<!-- 注意:bean的名字不要改,一定要叫multipartResolver -->
<bean name="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="UTF-8"/>
<!-- 指定所上传文件的总大小不能超过指定字节大小 -->
<property name="maxUploadSize" value="20000000"/>
</bean>
jsp页面代码:
<form action="upload/test" method="post" enctype="multipart/form-data">
<input type="file" name="file"><br>
<input type="file" name="file"><br>
<input type="submit" value="上传">
</form>
Controller中的代码:
@Controller
@RequestMapping("/upload")
public class UploadController {
@RequestMapping("/show")
public String showUploadPage(){
return "upload";
}
@RequestMapping("/test")
public String upload(@RequestParam("file") MultipartFile[] files, HttpServletRequest request) {
if (files != null && files.length > 0) {
for (MultipartFile file : files) {
// 保存文件
saveFile(request, file);
}
}
// 重定向
return "redirect:/upload/show";
}
private void saveFile(HttpServletRequest request, MultipartFile file) {
// 判断文件是否为空
if (!file.isEmpty()) {
try {
//保存的文件路径
//需要的话可以给文件名上加时间戳
String filePath = request.getServletContext().getRealPath("/") + "upload/"
+ file.getOriginalFilename();
File newFile = new File(filePath);
//文件所在目录不存在就创建
if (!newFile.getParentFile().exists()){
newFile.getParentFile().mkdirs();
}
// 转存文件
file.transferTo(newFile);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
注意:在上传文件的同时,还可以接收其他正常的单个的值,例如username、age等,同时也可以把这些单个的值自动封装成User对象
6.SpringMVC中下载
SpringMVC的下只需要自己设置response信息中的各个部分就可以,可以使用之前学习过的ResponseEntity<T>来完成
@RequestMapping("/show")
public String showDownLoadPage(){
return "download";
}
@RequestMapping("/test")
public ResponseEntity<byte[]> test(String fileName,HttpServletRequest request) throws IOException {
//获得下载文件所在路径 可以指向系统中的任意一个有权访问的路径
String downLoadPath = request.getServletContext().getRealPath("/download");
//创建要下载的文件对象
File file = new File(downLoadPath,fileName);
//处理一下要下载的文件名字,解决中文乱码
String downFileName = new String(fileName.getBytes("UTF-8"), "iso-8859-1");
//创建响应头信息的对象
HttpHeaders headers = new HttpHeaders();
//设置下载的响应头信息,通过浏览器响应正文的内容是用户要下载的,不用浏览器解析
headers.setContentDispositionFormData("attachment", downFileName);
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
//通过响应内容、响应头信息、响应状态来构建一个响应对象并返回
return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file), headers, HttpStatus.CREATED);
}
页面代码:
<a href="download/test?fileName=测试.txt">点击下载</a>
7.ajax上传文件
在上面普通上传的例子中进行修改即可
1)spring中配置上传的解析器
<bean name="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="UTF-8"/>
<property name="maxUploadSize" value="20000000"/>
</bean>
2)页面中引入jquery以及ajax上传的插件
ajax上传的插件有很多,这里使用的一个插件为:ajaxfileupload.js
注意引入的先后顺序不能乱
<script type="text/javascript" src="js/jquery-1.8.3.min.js"></script>
<script type="text/javascript" src="js/ajaxfileupload.js"></script>
3)jsp页面代码及其对应js代码
<script type="text/javascript">
$(function(){
$("input:button").on("click",function(){
if(!$("input:file").val()){
alert("请选择上传文件");
return;
}
ajaxFileUpload();
});
});
function ajaxFileUpload(){
$.ajaxFileUpload(
{
url: 'ajax_upload/test',
secureuri: false,
fileElementId: 'myfile',
dataType: 'text',
success: function (data){
$("input:file").val("");
$("#sp").html(data).css("color","green");
},
error: function (data){
$("#sp").html(data).css("color","red");
}
}
);
}
</script>
<body>
<!-- ajax上传不需要表单 -->
<!-- 这个上传框的id值一定要写,需要和js中的设置对应 -->
<input id="myfile" type="file" name="myfile"><br>
<input type="button" value="上传"><br>
<span id="sp"></span>
</body>
4)Controller中功能处理函数的代码
@Controller
@RequestMapping("/ajax_upload")
public class AjaxUploadController {
@RequestMapping("/show")
public String show(){
return "ajax_upload";
}
@RequestMapping(value="/test",method=RequestMethod.POST)
@ResponseBody
public String upload(@RequestParam(value="myfile",required=false) MultipartFile[] files, HttpServletRequest request) throws Exception {
if (files != null && files.length > 0) {
for (MultipartFile file : files) {
saveFile(request, file);
}
}
//这里要解决中文乱码问题
return new String("上传成功".getBytes("utf-8"),"iso-8859-1");
}
private void saveFile(HttpServletRequest request, MultipartFile file) {
if (!file.isEmpty()) {
try {
String filePath = request.getServletContext().getRealPath("/") + "upload/"+ file.getOriginalFilename();
File newFile = new File(filePath);
if (!newFile.getParentFile().exists()){
newFile.getParentFile().mkdirs();
}
file.transferTo(newFile);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
8.SSM框架的搭建
注意:
1.SpringMVC和Spring
不需要什么特殊的配置就可以结合
2.MyBatis和Spring
1)需要引入额外的jar包:mybatis-spring-1.3.2.jar
2)配置数据源
3)把MyBatis中的SqlSessionFactory配置给Spring管理
4)在spring中配置需要扫描的MyBatis映射接口所在包的位置
3.Spring中配置SqlSessionFactory
1)可以在MyBatis的mybatis-config.xml中把MyBatis的信息配好,然后再让spring读取这个mybatis-config.xml文件
2)可以删除mybatis-config.xml文件,然后MyBatis的信息都配置到Spring中
4.spring配置文件中的重要信息
可以写在外部的资源文件中,然后再使用spring的标签读出来使用
例如:
<context:property-placeholder location="classpath:db.properties"/>
取值使用的形式:${key}
${driverClassName}
5.事务配置
1)事务的开启和提交需要配置在service层方法的俩端
2)配置事务需要三步
配置事务管理器
使用jdbc的事务管理器
配置事务拦截器
使用tx前缀的标签
spring的aop配置(把事务管理织入到指定的切入点)
使用aop前缀的标签
6.日志配置
1)使用之前MyBatis的日志文件即可
2)在log4j.properties文件中可以屏蔽掉spring日志(输出太多了...)
#ALL DEBUG INFO WARM ERROR FATAL OFF
log4j.logger.org.springframework = ERROR
7.web.xml文件配置
1)配置spring读取的配置文件
2)配置编码过滤
3)配置前端控制器
8.SpringMVC的容器和Spring核心容器的关系
1)使用xml或者注解进行配置,springMVC或者spring读取配置信息之后,会把配置的对象(就是spring中的bean)放到容器中进行管理
2)服务器启动的时候,SpirngMVC中的前端控制器会读取配置文件,把相关配置的对象放到自己产生的容器中进行管理(需要在web.xml配置)
3)服务器启动的时候spring也会读取配置文件,把相关配置的对象放到自己产生的容器中进行管理(需要在web.xml配置)
4)SpirngMVC创建容器中所管理的Bean一般是只对SpringMVC有效,如Controller、HandlerMapping、HandlerAdapter等等(因为它一般只读取SpringMVC的配置文件)
5)Spirng创建容器中所管理的Bean一般是对于整个应用程序共享的,一般如DAO层、Service层Bean。(因为它一般只读取service层和dao层的配置文件)
6)SpirngMVC创建的容器 【继承了】 Spirng创建的容器
7)子容器可以从父容器中拿出bean来使用,但是父容器不能从子容器中拿bean来使用。所以在Controller中可以注入service层的实现类对象,Controller在SpringMVC创建的容器中,service是在Spring创建的容器中。
9.具体实例参照SSM项目