批量删除需要传递一堆id 所以参数类型为整型数组
"checkbox" value="${item.s_id }" name="ids">
@RequestMapping("deleteStudents.action")
public String deleteStudents(Integer[] ids) {
System.out.println(Arrays.toString(ids));
return "forward:getStudents.action";
}
数据比较复杂 SpringMVC中不支持list直接作为参数 使用包装类来接收
用来包装Student集合
public class Studenteger {
private List stus;
public List getStus() {
return stus;
}
public void setStus(List stus) {
this.stus = stus;
}
@Override
public String toString() {
return "Studenteger [stus=" + stus + "]";
}
}
前端页面
<td><input value="${item.s_name }" name="stus[${s.index }].s_name">td>
<td><input value="${item.s_age }" name="stus[${s.index }].s_age">td>
<td><input value="${item.s_gender }" name="stus[${s.index }].s_gender">td>
处理器
@RequestMapping("updateStudents.action")
public String updateStudents(Studenteger s) {
System.out.println(s);
return "forward:getStudents.action";
}
Student更新时 需要传递 姓名 性别 年龄
姓名 性别 是字符串类型
年龄是整型 能够确定的是前台传递的参数是String类型
请求参数到达Controller方法前必然要经过转换
因此需要自定义参数转换器
所谓自定义参数转换器指定就是转换参数类型的具体代码
具体操作(实例String转Integer)
创建参数转换器 实现Converter接口
public class MyIntConverter implements Converter<String, Integer> {
@Override
public Integer convert(String param) {
System.out.println(param);
// 将字符串分割为单个字符
// 提取值在0-9之间的字符组成新的整型
char[] charArray = param.toCharArray();
String newParam = "";
for (char c : charArray) {
if (c >= '0' && c <= '9') {
newParam += c;
}
}
System.out.println("转换后的参数" + newParam);
return Integer.valueOf(newParam);
}
}
在配置文件注册需要的转换器
<mvc:annotation-driven conversion-service="converters">mvc:annotation-driven>
<bean name="converters" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<bean class="com.lanou.converter.MyIntConverter">bean>
property>
bean>
SpringMVC框架会在接收到请求后 自动执行转换器中的代码 最后将转换结果交给Controller使用
用来将请求路径与处理器的分发进行绑定
value 类型: 数组
支持一个或多个字符串
多个需要用大括号包裹
例如:@RequestMapping(value={"test","myTest"})
此时无论请求test还是mytest都会执行对应的方法
method 类型: RequestMethod枚举数组
一个或多个
注意:如果设置为单个POST那该请求仅支持POST 如果类型不匹配会抛出异常(GET也一样)
多个需要用大括号包裹 例如
method= {RequestMethod.POST,RequestMethod.GET}
consumes 类型: 字符串
用于设置请求支持的Content-type 一般不做修改 支持任何类型的Content-type
produces 类型: 字符串
用于设置返回数据的Content-type(告诉浏览器如何解析)
该属性通常用于设置返回数据的编码
例如:produces="text/html;charset=utf-8"
params 类型: 字符串数组
用于限制请求需要的参数和条件
例如 params="id=100"
表示该请求必须包含id参数 并且值必须为100
headers 类型: 字符串数组
用于设置Header请求头中所包含的键值对
处理机制:
dao层抛给Service抛给Controller抛给控制器
核心控制器会在容器中找一个异常处理器对象
1.创建异常处理类 实现HandlerExceptionResolver
public class MyExceptionHandle implements HandlerExceptionResolver{
// 当在处理某个请求方式异常时 将自动调用该方法进行处理
// 第三个参数表示异常位置
// 返回值 ModelAndView 用来决定错误时显示的页面 以及数据
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object location,
Exception e) {
System.out.println("异常发生的位置" + location);
System.out.println("异常" + e);
// 发生异常后进入exception.jsp
// 并将位置和错误信息传给页面展示
// 对于系统异常 我们没有办法具体处理 因为不知道为什么发生
// 对于自己定义的已知异常 就可以进行具体的处理
ModelAndView mv = new ModelAndView();
if (e instanceof MyException) {
System.out.println(((MyException) e).getMsg());
mv.addObject("msg", ((MyException) e).getMsg());
}
mv.setViewName("exception.jsp");
mv.addObject("location", location);
return mv;
}
}
2.将这个类注册到容器中
<bean class="com.lanou.exception.MyExceptionHandle">bean>
使用异常处理器 对于自定义可以根据不同异常进行具体的处理
@RequestMapping("getStudents.action")
public String getStudents(Model model) {
// 模拟异常
//int a = 1/0;
List students = studentService.getStudents();
// 使用自定义的异常
if (students.size() < 10) {
throw new MyException("人数不够");
}
// 将数据放到model中
model.addAttribute("student", students);
return "list.jsp";
}
实现给学生上传头像
1.给学生表添加头像字段保存图片路径
2.修改响应的实体类与映射文件
思路:
上传文件后保存到指定的路径
数据库中存储图片的名字
1.通常我们会将收到的文件放在服务器的某个路径下
不要放在编辑器中 因为Tomcat发布项目时是为其创建了一个新的路径
这样会导致一个问题 放在编辑器中的文件不会立马进入Tomcat项目路径
Tomcat中可以添加虚拟路径 来简化代码
例如 原路径: /user/local/project/myProject/images
在页面中访问的话 写起来比较麻烦
我们可以配置虚拟路径
/user/local/project/myProject = > myProject
最终通过 myProject/images 来访问
2.也可以使用相对于classpath的路径
页面上提交表单时 设置input的type为file
<img alt="头像" src="/images/${student.s_image }" width="200px" height="100px"/>td>
<input type="file" name="photo">
form表单中的enctype为multipart/form-data
enctype="multipart/form-data"
表示不对提交的数据进行任何的编码
接收文件的参数类型 设置为MultipartFile
@RequestMapping("updateStudent.action")
public String updateStudent(Student stu,MultipartFile photo) throws IllegalStateException, IOException {
}
配置文件中 配置一个文件解析器
<bean name="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="5000000">property>
bean>
将收到的文件 存储至指定的路径下
// 将收到的文件搞到硬盘上去
// 随机一个文件名 32长度的字符串
String fileName = UUID.randomUUID().toString();
// 获取后缀名 getOriginalFilename() 整个原始文件名
String extension = FilenameUtils.getExtension(photo.getOriginalFilename());
// 获取路径
File file = new File("/Users/lanou/Documents/images/"+fileName+"."+extension);
// 存到指定硬盘路径
photo.transferTo(file);
保存文件名数据到数据库
// 拼接文件名
String newFile = fileName + "." + extension;
stu.setS_image(newFile);
studentService.updateStudent(stu);
return "forward:getStudents.action";
SpringMVC拦截器与servlet中的过滤器是一个原理
如果同时存在 web中的filter与MVC中的过滤器,先执行web中的filter
因为SpringMVC拦截器是SpringMVC中的一个组件
只有请求以及交给了SpringMVC 拦截器才有可能执行
编写拦截器类 实现HandlerInterceptor
public class MyIntercept implements HandlerInterceptor{
/*
* 处理器执行前
* 返回值用来控制是否要执行对应的控制器代码
* 返回false不执行
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("处理器执行前1");
return true;
}
// 处理执行后 没有异常才会执行
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("处理执行后1");
}
// 视图渲染完成后 也就是在jsp或html页面显示完成后执行
// 无论处理器是否有异常都会执行
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("视图渲染完成后1");
}
}
在配置文件中注册拦截器
<mvc:interceptors>
// 通用拦截器 所有请求都拦截
<bean class="com.lanou.intercept.MyIntercept">bean>
<mvc:interceptor>
// 只拦截/deleteStudents.action"请求
<mvc:mapping path="/deleteStudents.action"/>
<bean class="com.lanou.intercept.MyIntercept2">bean>
mvc:interceptor>
mvc:interceptors>
JSON用来接收更加复杂的数据,避免使用POJO创建很多不必要的实体类
1、请求时发送json格式的数据到后台
2、后台接口参数类型 Stirng
并添加@RequestBody
@RequestBody表示不需要SpringMVC进行解析
直接把接收的参数传到方法中
3、将收到的json字符串解析 并转换为实体对象
4、如果使用ajax请求name后台就不能返回一个页面
而应该返回普通字符串或是json格式字符串
5、前台收到json后进行解析并将数据展示到页面中
@RequestMapping(value="testAjaxRequest.action")
@ResponseBody
public String ajaxRequest(@RequestBody String jsonString){
// 将字符串转为json对象
JSONObject jsonObject = JSON.parseObject(jsonString);
// 将json对象转为实体类对象
Student student = JSON.toJavaObject(jsonObject, Student.class);
System.out.println(student);
// 将集合转换为json格式字符串
List stus = studentService.getStudents();
String jsonStr= JSON.toJSONString(stus);
// 创建一个json对象
JSONObject j = new JSONObject();
// 添加键值对
j.put("name", "张三");
j.put("age", 18);
j.put("code", 200);
// 创建一个json数组
JSONArray ja = new JSONArray();
// 在数组中添加一个小json表示这个人有几辆车
JSONObject car = new JSONObject();
car.put("carName", "奔驰");
ja.add(car);
// 将数组加到大的json对象中
j.put("cars", ja);
//"{'name':'张三','age':20,'cars':[{'carName':'奔驰'}]}"
return j.toJSONString();
}