springMVC
在controller中获取web元素
我们这里所说的web是:HttpServletRequest,HttpServletResponse,HttpSession,ServletContext 目前我们使用Controller中没有传入这些元素,其实spring不太建议使用这些元素,提供了专门的API。 当然也提供了非常简单的获取这些元素的方式,
如果我们希望在Handler中使用request,response,session这三个元素,直接作为形参即可。
}
}
return “web-element”;//逻辑视图
14
15
16
17
10
- //这里的request和response同样的可以做重定向和转发
- //request.getRequestDispatcher(“WEB-INF/jsp/web- element.jsp”).forward(request,response);
- //如果在这里手动的做了重定向或者转发,则直接return即可。 当前的方法就不需要返
回值。
@RequestMapping
public String getWebElement(HttpServletRequest request, HttpServletResponse response, HttpSession session) throws ServletException, IOException {
request.setAttribute(“reqAttr”,”request的属性值”);
session.setAttribute(“sessAttr”,”session 的 属 性 值 “); session.getServletContext().setAttribute(“appAttr”,”application的属
性值”);
7
8
9
- @Controller
- @RequestMapping(“/web”)
- public class WebElementController { 4
handler的各种不同的返回值处理
问题
我们这里说的handler就是controller中的有@RequestMapping注解的方法。已经知道的知识点:
- 如果注解了@ResponseBody,那么返回的任何内容都会以字符串形式输出到客户端。
如果返回的不是字符,而是对象,则自动转换为json格式输出。当然需要对应的jackson包和开启MVC 注解驱动。
- 没有@ResponseBody注解。 返回字符串,这是字符串就是视图。
springMVC的视图解析会自动判断是转发还是重定向。 还有哪些类型没说?
void?? 没有@ResponseBody,但是返回了一个对象??一个集合???
ModelAndView
模型和视图 这里的模型指的是数据模型。 这里的模型就是数据对象。所以,其实可以翻译为:数据和视图
案例: 我们要查询所有学生的列表,并且展示在JSP中:
@RequestMapping(“/queryAll”) public ModelAndView queryAll(){
ModelAndView modelAndView = new ModelAndView();
//查询所有学生
List
//request.setAttribute(“students”,students); modelAndView.addObject(“students”,students);
//request.getRequestDispatcher(“WEB-INF/jsp/student- list.jps”).fxxxxx
modelAndView.setViewName(“student-list”); return modelAndView;
}
}
15
16
17
18
- @Controller
- @RequestMapping(“/student”)
- public class StudentController {
- @Autowired
- private StudentService studentService; 6
7
8
9
10
11
12
13
14
说明:
//2 如果传入的是一个对象,则request的属性的key是 对象类型的类名首字母小写。
addAllObjects(传入一个Map);// 自己思考一下。
List
//
10
11
12
- ModelAndView对象包含了数据和视图信息。
- 并非数据和视图都是必须的,都是非必须。
- 添加数据的方式有多种:
- [1]创建对象的同时传入视图的名称和数据
- new ModelAndView(视图名称,数据属性名称,数据对象);
- [2]创建好对象之后,在使用addXXXAPI添加数据
- addObject(“attrName”,data);
- addObject(data);
- //1 如果传入的是一个List或者Set,则request属性的key是集合泛型类型的类名的首字母小写—+List,比如
返回逻辑使用,使用Model绑定数据
我们正常的返回一个逻辑视图,但是需要将数据放在request的作用域中。
上一小节,使用了ModelAndView。如果返回一个逻辑视图,可有其他的操作。 我们使用Model(这是我最常用的方式)
}
model.addAttribute(“students”,students);
return “student-list”;
这里的model是作为形参传递的
//给model添加属性
@RequestMapping(“/queryAll”)
public String queryAll(Model model){
List
1
2
3
4
5
6
7
说明:
spring自动会将这些数据放在request的作用域。
model对象不是自己创建的,是spring创建并且传递进来的。
model有4个对应的添加属性的API:
Model addAttribute(String attributeName, @Nullable Object attributeValue); Model addAttribute(Object attributeValue);
Model addAllAttributes(Collection<?> attributeValues);
Model addAllAttributes(Map
1
2
3
4
5
6
7
8
返回void
当一个handler方法返回void的时候,也同样会经过视图解析器进行转发。
void没有任何值,默认会直接直接转发到当前handler的url:
1 /*
2 @author 张双虎
3 */
- @Controller
- public class TeacherController {
- @Autowired
- private TeacherService teacherService;
- @RequestMapping(“/teacher-lst”)
- public void teacherList(Model model){ 10
model.addAttribute(“teachers”,teacherService.queryAllByLimit(0,100));
- //没有返回值,则转发到当前的handler对应的url
- //也就相当于这里返回了 return “teacher-list” 其实就是进入 WEB- INF/jsp/teacher-list.jsp
13 }
14 }
有同学会感觉是在循环的跳转。
- 你请求的url : /teacher-list 这个url不会经过视图解析器
- 处理完成之后,转发的url teacher-list 但是这个url会经过视图解析器。—> WEB- INF/jsp/teacher-list.jsp
返回值是Map或者ModelMap
我们使用void的时候,如果要在request的作用域中设置数据。我们要使用Model。其实我们可以直接返回ModelMap或者Model
案例:
- //没有传递参数Model
- //返回值不是void
- @RequestMapping(“/teacher-list”)
- public ModelMap teacherList(){
- ModelMap modelMap = new ModelMap();
- //ModelMap添加属性的API
- modelMap.addAttribute(“teachers”,teacherService.queryAllByLimit(0,5));
- return modelMap;
- //我们没有指定视图,这时转发的效果和void一致。
- //转发到当前的handler的url 11 }
说明:
- ModelMap本身就是集成了LinkedHashMap,所以可以直接使用Map的API添加数据。
- 当然ModelMap也有自己的API,它的API和上面的Model的API一模一样。
既然ModelMap是继承了LinkedHashMap,我们可以考虑直接使用HashMap:
- //没有传递参数Model
- //返回值不是void
- @RequestMapping(“/teacher-list”)
- public Map teacherList(){
- Map map = new HashMap();
- //ModelMap添加属性的API
- map.put(“teachers”,teacherService.queryAllByLimit(0,5));
- return map;
- //我们没有指定视图,这时转发的效果和void一致。
- //转发到当前的handler的url 11 }
返回Collection集合
上面的案例中,都是可以同时在request的作用域中设置多个属性值的。
有时,我可能就只是查询一个列表,只要放一个就可以的,这时可以考虑直接放回一个列表
(colleaction)
当我们返回一个collection的时候,转发的情况和void一模一样。
①直接返回List集合
- //没有传递参数Model
- //返回值不是List
- @RequestMapping(“/teacher-list”)
- public List teacherList(){
- return teacherService.queryAllByLimit(0,100);
- //我们没有指定视图,这时转发的效果和void一致。
- //转发到当前的handler的url 8 }
我们返回集合,spring会将这个集合直接设置到request的作用域中。没有指定request中属性的名字。 默认有个名字 集合泛型类型的类名的首字母小写+List
②直接返回set
- //没有传递参数Model
- //返回值不是List
- @RequestMapping(“/teacher-list”)
- public Set teacherList(){
- return new HashSet<>(teacherService.queryAllByLimit(0,100));
- //我们没有指定视图,这时转发的效果和void一致。
- //转发到当前的handler的url 8 }
tips:当使用set的时候,默认的key已然是 xxxList 而不是 xxxSet
返回一个对象
返回一个对象,并且没有注解@ResponseBody 转发情况和void一致。
并且spring会将这个对象设置到request的作用域,key 自己思考。
- @RequestMapping(“/teacher-detail”)
- public Teacher queryById(long teacherId){
- return teacherService.queryById(teacherId); 4 }
高级参数绑定
路径中的正则表达式
restFul风格:
RESTFUL特点包括: 1、每一个URI代表1种资源; 2、客户端使用GET、POST、PUT、DELETE4个表示操作方式的动词对服务端资源进行操作:GET用来获取资源,POST用来新建资源(也可以用于更新资 源),PUT用来更新资源,DELETE用来删除资源; 3、通过操作资源的表现形式来操作资源; 4、资源的表现形式是XML或者HTML; 5、客户端与服务端之间的交互在请求之间是无状态的,从客户端到服务端的每个请求都必须包含理解请求所必需的信息。
传统的url | restFul |
---|---|
POST请求:userSave?id=xx | POST: user/save/id/name |
GET请求: queryById?id=9527 | GET: query/9527 |
POST请求: update?id=9527&.. | PUT: update/9527/kakaxi |
GET请求: delete?id=9527 | DELETE: delete/9527 |
昨天已经讲过了在路径中携带参数。
今天来看看路径中携带一个正则表达式的参数:
1 /*
2 @author 张双虎
3 */
- @Controller
- public class RestFullController {
- //路径中的额参数是一个正则表达式
- @RequestMapping(“/update/{userBirth:\d{4}-\d{2}-\d{2}}/birth”)
- @ResponseBody
- public String updateBirth(@PathVariable(“userBirth”) String birth){
- System.out.println(birth);
- return “传递的参数是:”+birth; 12 }
13 }
只要符合这个正则表达式要求的,都可以进入这个handler。
高级参数绑定
- 绑定一个数组
当我们提交的数据是个数组的时候,就可以使用数字直接接受。
- LOL
- DNF
- CF
- DOTA
- WOW 7
8
9
10
后端接受:
public String paramBindArray(int [] enjoy){ return Arrays.toString(enjoy);
}
//使用数组接收
@ResponseBody
@RequestMapping(“/param-bind-array”)
1
2
3
4
5
复杂类型的请求参数
- 学科名称:
- 学科描述:
- 学科名称:
- 学科描述:
- 学科名称:
- 学科描述:
14
15 16
17
从表单中可以看出,提交的数据中有一个subjects集合,这个集合的泛型就是Subject,集合中的每个对 象都有属性subjectname和subjectdesc。
绑定这种类型的数据,我们需要定义一个VO对象。
- POJO(Plain Ordinary Java Object)简单的Java对象。实体类。
- DTO 数据传输对象(DTO)(Data Transfer Object)。
- VO(View Object) 也是用来传输数据的,但是主要使用在View层。
我们定义一个SubjectVO。
1 /*
2 @author 张双虎
3 */
- public class SubjectVO {
- //当然也可以有其他的属性
- //必须有一个集合
- private List
subjects; - public List
getSubjects() { - return subjects; 10 }
- public void setSubjects(List
subjects) { - this.subjects = subjects; 13 }
14 }
我们就可以是用这个VO对象来接收这些复杂参数:
public SubjectVO paramBindVo(SubjectVO subjectVO){ return subjectVO;
}
//使用VO对象接收
@ResponseBody
@RequestMapping(“/param-bind-vo”)
1
2
3
4
5
测试:
springMVC的文件上传和下载
文件上传
springMVC是使用commons-fileupload完成文件的上传的。 前端还是跟之前一致的。
引入对应的依赖:
commons-fileupload commons-fileupload 1.4
在springMVC的配置文件中添加相关配置:
1
2
3
4
5
6
①必须配置
②id必须multipartResolver。后端处理:
1 @PostMapping(“/upload”)
2
3
@ResponseBody
//使用MultipartFile接收文件
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public String upload(@RequestParam(“head”) MultipartFile head, HttpSession session) throws IOException {
//获取文件名
String fileName = head.getOriginalFilename();
//获取指向临时文件的输入流
InputStream in = head.getInputStream();
//这里就常规的文件拷贝
String realPath = session.getServletContext().getRealPath(“/“); File f = new File(realPath+”temp\“+fileName);
OutputStream out = new FileOutputStream(f); int len = -1;
byte [] buff = new byte[1024]; while((len = in.read(buff))!=-1){
out.write(buff,0,len); out.flush();
};
in.close();
out.close(); return “ok”;
}
我们可以使用CommonsMultipartFile接收文件,API会更加简单。
- @RequestMapping(“/upload”)
- @ResponseBody //使用MultipartFile接收文件
- public String upload(@RequestParam(“head”) CommonsMultipartFile head, HttpSession session) throws Exception {
- //获取文件名
- String fileName = head.getOriginalFilename();
- //这里就常规的文件拷贝
- String realPath = session.getServletContext().getRealPath(“/“);
- File f = new File(realPath+”temp\“+fileName);
- //直接可以使用对应的api拷贝文件
- if(!head.getFileItem().isFormField()){//不是表单域,我就开始拷贝
- head.getFileItem().write(f); 12 }
13 return “ok”; 14 }
tips:我们使用CommonsMultipartFile接收文件时,要指定表单域的名字。
如果有多个文件,可以写多个参数。如果是一组同名的文件,也可以使用数组接收。
文件下载
完全可以直接使用response得到输出流,直接将文件输出即可 ,跟spring没有关系。
spring也提供了一些解决方案。
我们可以将返回值设置为ResponseEntity。
- @RequestMapping(“/download”)
- public ResponseEntity
downLoad(HttpSession session) throws IOException { - String realPath = session.getServletContext().getRealPath(“/“);
- File f = new File(realPath+”temp\msyql数据库隔离界别的弊端.png”);
- FileInputStream in = new FileInputStream(f);
- //准备和文件长度一致的缓冲区
- byte [] buff = new byte[in.available()];
- //一次性将文件数据读取到缓冲区中
- in.read(buff);
- //准备一个MultiValueMap 在其中设置header
- MultiValueMap map = new LinkedMultiValueMap();
- map.put(“content-disposition”,new ArrayList
(Arrays.asList(new String[]{“attachment;filename=msyql数据库隔离界别的弊端.png”}))); - //创建ResponseEntity 传入参数(数据,headermap,状态码)
- ResponseEntity
responseEntity = new ResponseEntity (buff,map, HttpStatus.OK); - return responseEntity; 16 }
这个方法有点弊端:文件会一次性被读入内容。所以,我们还是建议直接使用response。
1 /*
2 @author 张双虎
3 */
- @WebServlet(“/download”)
- public class DownLoadServlet extends HttpServlet {
- @Override
- protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- this.doPost(req,resp); 9 }
- @Override
- protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
- String serverPath = this.getServletContext().getRealPath(“/“);
- //设置响应头
- response.setContentType(“image/jpeg”);
- // attachment表示内容是一个附件, filename配置文件的名称
- response.addHeader(“content- disposition”,”attachment;filename=car123.jpg”);
- //通过response获取输出流(这个输出流就是指向客户端的)
- ServletOutputStream outputStream = response.getOutputStream();
- //读取文件
- FileInputStream inputStream = new FileInputStream(serverPath+”upload\car.jpg”);
- //文件拷贝的流程
- int len = -1;
- byte [] buff = new byte[1024];
- while((len = inputStream.read(buff))!=-1){
- outputStream.write(buff,0,len); 26 }
27 inputStream.close(); 28 }
29 }
30
spring对A JAX的支持
返回json格式的数据:略。接收json格式的数据:
前端提交json格式的数据:
- $(“#btn”).click(function(){
- //准备json格式的数据
- var subject =
{subjectid:9527,subjectname:”javaSE”,subjectdesc:”javajava”,status:1};
- //将对象转换为json字符串
- var jsonData = JSON.stringify(subject);
- console.log(jsonData);
- $.ajax({
- type:”POST”,
- url:”doAjax.action”,
- data:jsonData,
- contentType:”application/json”,
- success:function(res){
- alert(res);
15 }
16 });
17 });
18
后端接受:
}
public String doAjax(@RequestBody Subject subject){ System.out.println(subject);
return “ok”;
}
//接受json格式的数据,要注解@RequestBody
@ResponseBody
/*
@author 张双虎
*/ @Controller
public class AjaxController {
@RequestMapping(“/doAjax”)
1
2
3
4
5
6
7
8
9
10
11
12