响应
返回字符串以及void的情况
1.返回字符串 <br> <a href="responseController/returnString">returnString</a> <br> 2.没有返回值 <br> <a href="responseController/returnVoid">returnVoid</a> <br> 3.没有返回值,转发 <br> <a href="responseController/returnVoidAndDispatcher">returnVoidAndDispatcher</a> <br> 4.没有返回值,重定向 <br> <a href="responseController/returnVoidAndResponse">returnVoidAndResponse</a> <br> 5.没有返回值,转发到同一个控制器的其他映射方法 <br> <a href="responseController/returnVoidAndDispatcherToConreoller">returnVoidAndDispatcherToConreoller</a> <br> 6.没有返回值,重定向到其他控制器的其他映射方法 <br> <a href="responseController/returnVoidAndDispatcherToConreoller2">returnVoidAndDispatcherToConreoller2</a> <br>
@RequestMapping("/responseController") @Controller("responseController") public class _06ResponseController { /** * 1.测试返回字符串类型 * 指的是返回逻辑结果视图名称 * springMVC会以此返回值作为文件名,到视图解析器里面进行拼接成JSP页面,并最终跳转到该页面 */ @RequestMapping("/returnString") public static String returnString() { return "sucess"; } /** * 2.没有返回值 * 当我们的方法返回值是void时,springMVC会把@RequestMapping()里面的映射路径名作为返回值去视图解析器解析查找对应的页面 * 例如,这里会:HTTP Status 404 - /springMVC_war/WEB-INF/pages/responseController/returnVoid.jsp * 我们可以通过转发或者重定向跳转到指定的JSP页面或者其他的映射方法(控制器)里面 */ @RequestMapping("/returnVoid") public static void returnVoids() { System.out.println("returnVoid方法执行"); } /** * 2.1.转发到jsp */ @RequestMapping("/returnVoidAndDispatcher") public static void returnVoidAndDispatcher(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // /WEB-INF/下面的地址是服务器内部地址,我们使用转发访问 request.getRequestDispatcher("/WEB-INF/pages/sucess.jsp").forward(request, response); } /** * 2.2重定向到jsp */ @RequestMapping("/returnVoidAndResponse") public static void returnVoidAndResponse(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 重定向的方式只能访问服务器外部资源,所有我们在/WEB-INF/文件夹之外新建一个redirectView.jsp页面 System.out.println(request.getContextPath()); response.sendRedirect(request.getContextPath() + "/redirectView.jsp"); } /** * 2.3转发或者重定向到本控制器的其他控制方法 */ @RequestMapping("/returnVoidAndDispatcherToConreoller") public static void returnVoidAndDispatcherToConreoller(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 转发到同一个Controller下面的其他控制器方法(浏览器地址栏还是:***/responseController/returnVoidAndDispatcherToConreoller request.getRequestDispatcher("returnString").forward(request, response); //也可以使用重定向方法(浏览器地址栏变为:***/responseController/returnString // response.sendRedirect("returnString"); } /** * 2.4重定向其他控制器 * 跳转到其他控制器只能用重定向 */ @RequestMapping("/returnVoidAndDispatcherToConreoller2") public static void returnVoidAndDispatcherToConreoller2(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 重定向到其他Controller下面的控制器方法 // response.sendRedirect("test/hello");//不可用 // 重定向其他Controller需要加request.getContextPath(),否则只会在本Controller下面寻找目标路径 response.sendRedirect(request.getContextPath() + "/test/hello"); } }
原始servlet -API把响应数据带回浏览器
/** * 3.1.转发到jsp并传值 */ @RequestMapping("/returnValue") public static void returnValue(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // /WEB-INF/下面的地址是服务器内部地址,我们使用转发访问 request.setAttribute("username", "李沁"); request.setAttribute("password", "123456"); request.getRequestDispatcher("/WEB-INF/pages/sucess.jsp").forward(request, response); }
<html> <head> <title>成功页面</title> </head> <body> 执行成功 <%-- JSP四大域对象: page域 PageContext 最小页面范围,出了当前页面就失效 request域 ServletRequest 当前请求和当前请求的转发 一次请求用 session域 HttpSession 一次会话 多次请求用 application域 ServletContext 最大整个应用 --%> 后台传过来的username:${username}<%--相当于pageContext的getAttribute方法--%> 后台传过来的password:${requestScope.password}<%--明确从请求域中获取数据--%> </body> </html>
ModelAndView
/** * 4.ModelAndView * 返回ModelAndView,该对象是spring为我们提供的可以存放响应数据的对象。 * 它里面有两个方法: * setViewName:用于设置逻辑结果视图名称 * addObject(String,Object):用于设置响应正文的内容。存放的结构是key=value的形式。存入的位置是请求域中 */ @RequestMapping("/returnModelAndView") public ModelAndView returnModelAndView(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ModelAndView modelAndView = new ModelAndView(); ArrayList<String> list = new ArrayList<>(); list.add("1"); list.add("2"); list.add("3"); modelAndView.addObject("list",list); modelAndView.setViewName("modelAndView"); return modelAndView; }
modelAndView.jsp:
<%--导入jstl--%> <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>modelAndView</title> </head> <body> ${list} ${requestScope.list} <c:forEach items="${list}" var="str"> ${str} </c:forEach> </body> </html>
springMVC的转发和重定向
/** * springmvc的请求转发: */ @RequestMapping("/springmvcDispatcher") public static String springmvcDispatcher() { // 简写:写的是逻辑结果视图名称 // return "sucess"; // 完整写法:写的是物理视图地址 return "forward:/WEB-INF/pages/sucess.jsp"; } /** * springmvc的请求重定向: */ @RequestMapping("/springmvcRedirect") public static String springmvcRedirect() { // return "forward:/WEB-INF/pages/sucess.jsp";///WEB-INF/下面的内容我们是无法重定向进去的,下面我们演示重定向到springmvcDispatcher这个方法映射 return "redirect:springmvcDispatcher"; }
JSON数据的发送和返回
@ResponseBody:
@RequestBody:
<html> <head> <title>responseJson</title> </head> <script src="${pageContext.request.contextPath}/js/jquery-3.1.1.js"></script> <script> $(function () { $("#getJson").click(function () { alert(1) $.ajax({ type: "post",//请求的方式 url: "${pageContext.request.contextPath}/responseController/returnJson",//请求的地址 dataType: "json",//响应的数据格式 data: '{"id":1,"name":"李沁"}',//请求的正文(请求的参数) contentType: "application/json;charset=utf-8",//请求参数的格式 success: function (data) {//执行成功后的回调函数 alert(data) } }) }) }) </script> <body> returnJson测试响应ison数据 <br> <input type="button" value="提交" id="getJson"> </body> </html>
依赖支持:
<!-- 导入json支持jar--> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.9.6</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.9.6</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.6</version> </dependency>
/** * 7.测试响应ison数据 * 应用场景: * 一般都是异步请求,不希望浏览器刷新。 * @ResponseBody:将返回值的对象封装成json格式之后返回 * @RequestBody:将前台传递过来的json字符串封装成对应的对象 */ @RequestMapping("/returnJson") public @ResponseBody Account returnJson(@RequestBody Account accountJson) { System.out.println(accountJson); return accountJson; }
文件上传:
1.传统方式:
参考:https://www.cnblogs.com/luzhanshi/p/13285516.html
2.springMVC提供的方式:
所需依赖:
<!-- 上传文件所需jar包--> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.3</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.4</version> </dependency>
springMVC.xml新增配置:
<!-- 配置springmvc提供的文件解析器--> <!-- 注意:!!!下面的id只能是multipartResolver!!!--> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!-- 配置上传文件的最大尺寸为10M--> <property name="maxUploadSize"> <value>10240000</value> </property> </bean>
前台代码:
<body> <form action="springMVCfileUploadController/fileUploadtest" method="post" enctype="multipart/form-data"> 名称: <input type="text" name="text"><br> 图片:<input type="file" name="file" multiple="multiple" accept="image/png,image/gif,image/jpeg, image/jp2,.txt" ><br> <input type="submit"><br> </form> </body>
后台代码:
@RequestMapping("/springMVCfileUploadController") @Controller("springMVCfileUploadController") public class _08springmvcFileUploadController { @RequestMapping("/fileUploadtest") public ModelAndView fileUploadtest(String text, MultipartFile file, HttpServletRequest request) throws Exception { System.out.println("文件上传方法执行了"); System.out.println(text); // 1.设置保存目录 File fatherDir = new File("D:\fileUpload"); // 2.为防止文件过多,以日期为名创建子文件夹储存位置 String childDir = new SimpleDateFormat("yyyy-MM-dd").format(new Date()); File targetDir = new File(fatherDir, childDir); if (!targetDir.exists()) { targetDir.mkdirs(); } // 3.获取上传文件名,并随机化 String fileName = file.getOriginalFilename(); String uuid = UUID.randomUUID().toString(); String newFileName = uuid + "_" + fileName; // 4.写入文件 file.transferTo(new File(targetDir, newFileName)); return "sucess"; } }
3.springMVC跨服务器上传:
在实际开发中,我们会有很多处理不同功能的服务器。例如:
应用服务器:负责部署我们的应用
数据库服务器:运行我们的数据库
缓存和消息服务器:负责处理大并发访问的缓存和消息
文件服务器:负责存储用户上传文件的服务器。
(注意:此处说的不是服务器集群)
分服务器处理的目的是让服务器各司其职,从而提高我们项目的运行效率。
所需依赖:
<!-- 上传文件所需jar包--> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.3</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.4</version> </dependency> <!-- 跨域上传文件额外所需jar包--> <!-- https://mvnrepository.com/artifact/com.sun.jersey/jersey-core --> <dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-core</artifactId> <!-- 我们一般在第二行直接写jar的名字,静静地等待maven给我们提示,然后回车补全,搞定--> <version>1.18.1</version> </dependency> <!-- https://mvnrepository.com/artifact/com.sun.jersey/jersey-client --> <dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-client</artifactId> <version>1.18.1</version> </dependency>
导入jersey 失败?请参考https://www.cnblogs.com/luzhanshi/p/13286405.html解决
springMVC.xml同样要新增配置:
<!-- 配置springmvc提供的文件解析器--> <!-- 注意:!!!下面的id只能是multipartResolver!!!--> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!-- 配置上传文件的最大尺寸为10M--> <property name="maxUploadSize"> <value>10240000</value> </property> </bean>
接收文件的Tomact服务器安装目录下的conf/web.xml配置文件中加上:(使得服务器允许文件写入。)
<init-param> <param-name>readonly</param-name> <param-value>false</param-value> </init-param>
否则会报如下错误:
接收文件的服务器项目要保证有如下目录:
否则会报如下错误:PUT http://localhost:9090/fileServer_War/upload/20160515104302348740.jpg returned a response status of 409 Conflict
发送文件前台代码:
<form action="springMVCTwoServerfileUploadController/fileUploadtest" method="post" enctype="multipart/form-data"> 名称: <input type="text" name="text"><br> 图片:<input type="file" name="file" multiple="multiple" accept="image/png,image/gif,image/jpeg, image/jp2" ><br> <input type="submit"><br> </form>
发送文件后台代码:
@RequestMapping("/springMVCTwoServerfileUploadController") @Controller("springMVCTwoServerfileUploadController") public class _08springmvcTwoServerFileUploadController { // 全局定义图片服务器路径 private static final String FILESERVERPATH = "http://localhost:9090/fileServer_war/upload/"; @RequestMapping("/fileUploadtest") public String fileUploadtest(String text, MultipartFile file, HttpServletRequest request) throws Exception { System.out.println("文件上传方法执行了"); System.out.println(text); // 1.获取上传文件名,并随机化 String fileName = file.getOriginalFilename(); String uuid = UUID.randomUUID().toString(); String newFileName = uuid + "_" + fileName; // 2.获取jersey的jar包中提供的Client对象 Client client = Client.create(); // 3.建立和图片服务器的联系 WebResource resource = client.resource(FILESERVERPATH + newFileName); // 4.把文件写到远程服务器(String.class决定返回值类型) String s = resource.put(String.class, file.getBytes()); System.out.println(s); return "sucess"; } }
演示效果
最后一定要去tomcat发布项目的目录下去查看文件是否上传成功!!!不要傻傻的去项目里面的upload目录下去看
自定义异常:
1.创建自定义异常类
/** * 客户自定义异常类;继承RuntimeException或者Exception */ public class MyException extends RuntimeException { // 定义异常信息 private String msg; //通过构造方法获取异常信息 public MyException(String msg) { this.msg = msg; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } }
2.创建自定义异常处理器:
/** * 自定义异常处理器(需要实现:HandlerExceptionResolver) * 并且要注册为speing组件,对象的创建交给speing容器管理,可以使用下面注解的方式,也可以在speingMVC.xml里面配置bean:<bean id="myExceptionResolver" class="web.pojo.MyExceptionResolver"></bean> */ @Component("myExceptionResolver") public class MyExceptionResolver implements HandlerExceptionResolver { @Override public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception e) { // 打印异常信息 e.printStackTrace(); // 定义自己的异常类对象 MyException myException = null; // 判断当前传入的异常对象是否是我们的自定义对象对象 if (e instanceof MyException) {//如果是,我们就直接强转为我们自定义的异常类型 myException = (MyException) e; } else {//否则就获取该异常的异常信息创建我们的自定义异常 myException = new MyException(e.getMessage()); } ModelAndView modelAndView = new ModelAndView(); modelAndView.setViewName("error"); modelAndView.addObject("errorMsg", myException.getMsg()); return modelAndView; } }
3.新建统一错误信息展示页面:
<html> <head> <title>失败页面</title> </head> <body> <%--注意!!!下面的"errorMsg"要和我们自定义异常处理器里面返回的错误信息字段名一致--%> ${errorMsg}; </body> </html>
4.测试代码:
@RequestMapping("/exceptionController") @Controller("exceptionController") public class _10exceptionController { @RequestMapping("testException") public String testException(String name) throws MyException { System.out.println("测试异常方法执行了"+name); if (StringUtils.isEmpty(name)) throw new RuntimeException("用户名不能为空"); // throw new MyException("用户名不能为空");//也可以抛出我们自定义异常 return "sucess"; } }
自定义拦截器:
拦截器:
Spring MVC的处理器拦截器类似于Servlet开发中的过滤器Filter用于对处理器进行预处理和后处理。用户可以自己定义一些拦 截器来实现特定的功能。
谈到拦截器;还要向太家提一个词一 拦截器链( Interceptor Chain)。 拦截器链就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。
说到这里,可能大家脑海中有了一个疑问;这不是我们之前学的过滤器吗?是的它和过滤器是有几分相似,但是也有区别,接下来我们就来说说他们的区别:
过滤器是Servlet规范中的一-部分,任何iava web工程都可以使用。
拦截器是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能用。
过滤器在url-pattern中配置了/*之后:可以对所有要访问的资源拦截。
拦截器它是只会拦截访问的控制器方法,如果访问的是j3R: html, ce image或者ia是不会进行拦
截的。
它也是AOP思想的具体应用。
我们要想自定义拦截器,要求必须实现: HandlerInterceptor接只。
举例:假如我们要对用户访问下面的路径的时候要验证用户是否已经登录,没有登录不可以访问:
@RequestMapping("/interceptorController") @Controller("interceptorController") public class _11interceptorController { @RequestMapping("/testInterceptor") public String testInterceptor(String name) { System.out.println("控制器中方法执行了"+name+" 说明用户登录了"); return "sucess"; } }
首先我们要编写一个拦截器:
//自定义拦截器实现HandlerInterceptor并重写所有的方法 public class CheckLoginInterceptor implements HandlerInterceptor { /** * preHandle * 当请求到达时,先执行此方法。 * 此方法的返回值决定了是否放行 * 返回true:放行放行的含义:如果有下一个拦截器执行下一个,如果该拦截器处于最后一个,则执行handler方法(控制器中的方法) * 返回false:不放行 */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("preHandle方法执行了"); // 1. 获取Session对象 HttpSession session = request.getSession(); // 2. 判断session域中是否有登录标记 Object userinfo = session.getAttribute("userinfo"); if (userinfo != null) { return true; } // 没有登录信息的情况下 跳转到登录页面 request.getRequestDispatcher("/WEB-INF/pages/login.jsp").forward(request, response); return false; } /** * postHandle * 如何调用: * 按拦截器定义逆序调用 * 何时调用: * 在拦截器链内所有拦戴器返成功调用 * 有什么用: * 在业务处理器处理完请求后,但是DiapatcherServlet向客户端返回响应前,在该方法中对用户请求request进行处理。 */ @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("postHandle方法执行了"); } /** * afterCompletion * 如何调用: * 按拦截器定义逆序调用 * 何时调用: * 只有preHandle返回true才调用 * 有什么用: * 在DiapatcherServlet完全处理完请求后被调用,可以在该方法中进行一些资源清理的操作。 */ @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("afterCompletion方法执行了"); } }
然后我们需要在springMVC.xml里面配置拦截器:
<!--配置自定义拦截器--> <mvc:interceptors> <mvc:interceptor> <!-- path="/interceptorController/**":表示拦截 interceptorController下面的所有映射路径 --> <mvc:mapping path="/interceptorController/**"/> <bean class="web.pojo.CheckLoginInterceptor" id="myInterceptor"></bean> </mvc:interceptor> </mvc:interceptors> </beans>
我们的登录login.jsp:
<body> <a href="${pageContext.request.contextPath}/login/userLogin">登录</a> <%--${pageContext.request.contextPath}:springMVC_war(项目的根目录)--%> </body>
登录的Controller代码:
@Controller("loginController") @RequestMapping("/login") public class LoginController { @RequestMapping("/userLogin") public String userLogin(HttpServletRequest request) { // 1.获取session request.getSession().setAttribute("userinfo", "..."); return "redirect:/main.jsp"; } }
main.jsp:
<body> 主页 </body>
上述文件的位置:
使得服务器允许文件写入。