示例:/** * 方法绑定属性中不允许的参数 */private final static String[] DISALLOWED_PARAMS = new String[]{"idObject.primarykey"};@InitBinderpublic void initBinder(WebDataBinder binder) { binder.setDisallowedFields(DISALLOWED_PARAMS);} 在添加和更新时,您应该禁止“id”字段。否则,恶意用户可能会篡改更新请求的“id”请求参数的值,从而将不同的记录更新为表单所示的记录(假设没有ACL或其他域级安全性)。 但是,如果您只是禁止“id”字段,控制器会将ID视为null,这在插入时有效,但在更新时无效(例如,它可能会尝试插入新记录而不是更新,具体取决于您的持久性机制'正在使用)。因此,您希望控制器记住请求之间的域对象的不可编辑值(不仅是ID,而是所有不允许的字段),以便它可以将所有正确的值发送到服务层或其他业务逻辑。这是使用类型级@SessionAttributes注释完成的。https://www.cnblogs.com/softidea/p/10078605.html
SpringMVC文件上传所需依赖<dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.1</version></dependency><dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.4</version></dependency>传统方式上传文件通用上传页<h3>文件上传</h3><form action="user/fileupload" method="post" enctype="multipart/form-data">选择文件:<input type="file" name="upload"/><br/><input type="submit" value="上传文件"/></form>从request中获取文件 @RequestMapping("/fileupload") public String fileuoload1(HttpServletRequest req) throws Exception { StandardMultipartHttpServletRequest request = (StandardMultipartHttpServletRequest) req; System.out.println("文件上传..."); // 使用fileupload组件完成文件上传 // 上传的位置 获取最大的目录 即webapp/WebRoot目录 String path = request.getSession().getServletContext().getRealPath("/uploads/"); // 判断,该路径是否存在 File file = new File(path); if (!file.exists()) { // 创建该文件夹 file.mkdirs(); } // 解析request对象,获取上传文件项 DiskFileItemFactory factory = new DiskFileItemFactory(); ServletFileUpload upload = new ServletFileUpload(factory); // 解析request List<FileItem> items = upload.parseRequest(request); // 遍历 for (FileItem item : items) { // 进行判断,当前item对象是否是上传文件项 if (item.isFormField()) { // 说明普通表单向 } else { // 说明上传文件项 // 获取上传文件的名称 String filename = item.getName(); // 把文件的名称设置唯一值,uuid String uuid = UUID.randomUUID().toString().replace("-", ""); filename = uuid + "_" + filename; // 完成文件上传 item.write(new File(path, filename)); // 删除临时文件(大于10k的都会生成临时文件 因此要删除) item.delete(); } } return "success"; }SpringMVC方式上传文件解析器配置springmvc.xml配置文件解析器:<!-- 配置文件解析器对象,要求id名称必须是multipartResolver 不能改--><bean id="multipartResolver"class="org.springframework.web.multipart.commons.CommonsMultipartResolver"><property name="maxUploadSize" value="10485760"/></bean>更多配置<!-- 多部分文件上传 --><bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="maxUploadSize" value="104857600" /> <property name="maxInMemorySize" value="4096" /> <property name="defaultEncoding" value="UTF-8"></property></bean>上述配置文件单位是Byte,10M就是10x1024x1024相乘的值上传大小异常处理 <!--配置文件解析器对象--> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="maxUploadSize" value="51200" /> </bean> <!-- 1.在文件上传解析时发现异常,此时还没有进入到Controller方法中 --> <bean id="exceptionResolver" class= "org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <property name="exceptionMappings"> <props> <!-- 遇到MaxUploadSizeExceededException异常时,跳转到error.jsp页面 --> <prop key= "org.springframework.web.multipart.MaxUploadSizeExceededException">/error </prop> </props> </property> </bean>上述即文件超过50k就跳转错误页面,报错就不会执行Controller里的代码了。也可以自定义异常类,如下:/** * 自定义异常处理器类 */public class ExceptionHandler implements HandlerExceptionResolver{ /** * 处理上传文件大小超过限制抛出的异常 */ @Override public ModelAndView resolveException(HttpServletRequest req, HttpServletResponse res, Object ob,Exception ex) { ModelAndView mv=new ModelAndView(); //判断异常类型,来跳转不同页面 if (ex instanceof MaxUploadSizeExceededException){ //指定错误信息 mv.addObject("errormessage", "上传文件过大"); //设置跳转视图 mv.setViewName("userEdit"); return mv; } //其他异常 return null; }}然后将其加入springmvc.xml中即可<bean class="com.cheng.exception.ExceptionHandler" />由于Tomcat问题,7.0系列版本在上传大文件如果超过大小限制会直接页面连接断开。这时可以不用SpringMVC自带的解析器限制文件大小,而是通过代码实现。配置拦截器public class FileUploadInterceptor extends HandlerInterceptorAdapter { private long maxSize; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //判断是否文件上传 if(request!=null && ServletFileUpload.isMultipartContent(request)) { ServletRequestContext ctx = new ServletRequestContext(request); //获取上传文件尺寸大小 long requestSize = ctx.contentLength(); if (requestSize > maxSize) { //当上传文件大小超过指定大小限制后,模拟抛出MaxUploadSizeExceededException异常 throw new MaxUploadSizeExceededException(maxSize); } } return true; } public void setMaxSize(long maxSize) { this.maxSize = maxSize; }}配置解析器 <!-- 配置文件上传类型解析器 multipartResolver--> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver" /> <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**"/> <bean class="cn.cheng.controller.FileUploadInterceptor"> <!-- 设定限制的文件上传大小 --> <property name="maxSize" value="51200"/> </bean> </mvc:interceptor> </mvc:interceptors>上传格式异常处理第一种在Controller方法中限制,但每次都写太过于麻烦,第二种使用拦截器,下列是后者:public class FileTypeInterceptor extends HandlerInterceptorAdapter { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception { boolean flag= true; // 判断是否为文件上传请求 if (request instanceof MultipartHttpServletRequest) { MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request; Map<String, MultipartFile> files = multipartRequest.getFileMap(); Iterator<String> iterator = files.keySet().iterator(); //对多部件请求资源进行遍历 while (iterator.hasNext()) { String formKey = (String) iterator.next(); MultipartFile multipartFile = multipartRequest.getFile(formKey); String filename=multipartFile.getOriginalFilename(); //判断是否为限制文件类型 if (! checkFile(filename)) { //限制文件类型,请求转发到原始请求页面,并携带错误提示信息 request.setAttribute("errormessage", "不支持的文件类型!"); request.getRequestDispatcher("/WEB-INF/pages/typeerror.jsp") .forward(request, response); flag= false; } } } return flag; } /** * 判断是否为允许的上传文件类型,true表示允许 */ private boolean checkFile(String fileName) { //设置允许上传文件类型 String suffixList = "jpg,gif,png,ico,bmp,jpeg"; // 获取文件后缀 String suffix = fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length()); if (suffixList.contains(suffix.trim().toLowerCase())) { return true; } return false; }}xml配置文件配置拦截器,注意先后顺序 <mvc:interceptors> <mvc:interceptor> <!-- /**表示所有URL和子URL路径 --> <mvc:mapping path="/**"/> <!-- 配置自定义的文件上传类型限制拦截器 --> <bean class="cn.cheng.controller.FileTypeInterceptor"/> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/**"/> <bean class="cn.cheng.controller.FileUploadInterceptor"> <!-- 设定限制的文件上传大小 --> <property name="maxSize" value="512000000000"/> </bean> </mvc:interceptor> </mvc:interceptors>这样无论传多大都不会错,但是格式不正确会被跳转到错误页面。拦截器返回Json数据很多时候经常用ajax与json进行数据交互,因此并不一定每次出错都是跳转页面,返回json也很简单,直接写在拦截器response对象中即可response.setCharacterEncoding("UTF-8");response.setContentType("application/json; charset=utf-8");PrintWriter out = null ;try{ JSONObject res = new JSONObject(); res.put("success","false"); res.put("msg","上传文件类型错误"); out = response.getWriter(); out.append(res.toString()); return false;}catch (Exception e){ e.printStackTrace(); response.sendError(500); return false;}当然我们也可将其封装成工具类public class SendMsgUtil { /** * 将某个对象转换成json格式并发送到客户端 * @param response * @param obj * @throws Exception */ public static void sendJsonMessage(HttpServletResponse response, Object obj) throws Exception { response.setContentType("application/json; charset=utf-8"); PrintWriter writer = response.getWriter(); writer.print(JSONObject.toJSONString(obj, SerializerFeature.WriteMapNullValue, SerializerFeature.WriteDateUseDateFormat)); writer.close(); response.flushBuffer(); }}用MultipartFile的transferTo代码: @RequestMapping("/fileupload2") public String fileuoload2(HttpServletRequest request, MultipartFile upload) throws Exception { System.out.println("springmvc文件上传..."); // 使用fileupload组件完成文件上传 // 上传的位置 String path = request.getSession().getServletContext().getRealPath("/uploads/"); // 判断,该路径是否存在 File file = new File(path); if (!file.exists()) { // 创建该文件夹 file.mkdirs(); } // 说明上传文件项 // 获取上传文件的名称 String filename = upload.getOriginalFilename(); // 把文件的名称设置唯一值,uuid String uuid = UUID.randomUUID().toString().replace("-", ""); filename = uuid + "_" + filename; // 完成文件上传 new File中做目录 又文件名 upload.transferTo(new File(path, filename)); return "success"; }其中用文件参数类型用CommonsMultipartFile亦可,但是这时必须给参数@RequestParam("file")注解指定所传文件项!CommonsMultipartFile的getFileItem() @RequestMapping("/fileupload2") public String fileuoload2(HttpServletRequest request, @RequestParam("upload") CommonsMultipartFile upload) throws Exception { System.out.println("springmvc文件上传..."); // 使用fileupload组件完成文件上传 // 上传的位置 String path = request.getSession().getServletContext().getRealPath("/uploads/"); // 判断,该路径是否存在 File file = new File(path); if (!file.exists()) { // 创建该文件夹 file.mkdirs(); } // 说明上传文件项 // 获取上传文件的名称 String filename = upload.getOriginalFilename(); String uploadFileFileNameWithoutSpace = filename.replaceAll(" ", ""); File targetFile = new File(path + File.separator, uploadFileFileNameWithoutSpace); //判断目标文件存在就删除 其实只要保证文件名唯一就无需该操作 if (targetFile.exists()) { targetFile.delete(); } upload.getFileItem().write(targetFile); return "success"; }其中File.separator等效于分隔符"/",当然也可以拼接这个分隔符,按常理说windows系统路径分隔符是\,使用时候需转义为\\,Linux是/,因此separator可以对系统进行判断返回相应分隔符。多文件上传 @RequestMapping("fileupload22") public String springUpload(HttpServletRequest request) throws IllegalStateException, IOException { long startTime = System.currentTimeMillis(); //将当前上下文初始化给 CommonsMutipartResolver (多部分解析器) // 上传的位置 String path = request.getSession().getServletContext().getRealPath("/uploads/"); CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver( request.getSession().getServletContext()); //检查form中是否有enctype="multipart/form-data" if (multipartResolver.isMultipart(request)) { //将request变成多部分request MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request; //获取multiRequest 中所有的文件名 Iterator iter = multiRequest.getFileNames(); while (iter.hasNext()) { //一次遍历所有文件 MultipartFile file = multiRequest.getFile(iter.next().toString()); if (file != null) { String filepath = path + "/" + file.getOriginalFilename(); System.out.println(filepath); //上传 file.transferTo(new File(filepath)); } } } long endTime = System.currentTimeMillis(); System.out.println("运行时间:" + (endTime - startTime) + "ms"); return "success"; }跨服务器上传有专门的图片服务器B,用户访问网站在A服务器,在A网站上传图片被转存到B服务器,A服务器不作储存。首先我们需要两个tomcat。依赖:<dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-core</artifactId> <version>1.18.1</version></dependency><dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-client</artifactId> <version>1.18.1</version></dependency>实例代码创建端口不同的tomcat的web项目,在WEB-INF里建uploads文件夹,修改web.xml配置文件<web-app> <display-name>Archetype Created Web Application</display-name> <servlet> <servlet-name>default</servlet-name> <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class> <init-param> <param-name>debug</param-name> <param-value>0</param-value> </init-param> <init-param> <param-name>readonly</param-name> <param-value>false</param-value> </init-param> <init-param> <param-name>listings</param-name> <param-value>false</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet></web-app>代码: @RequestMapping("/fileupload3") public String fileuoload3(MultipartFile upload) throws Exception { System.out.println("跨服务器文件上传..."); // 定义上传文件服务器路径 String path = "http://localhost:9090/uploads/"; // 说明上传文件项 // 获取上传文件的名称 String filename = upload.getOriginalFilename(); // 把文件的名称设置唯一值,uuid String uuid = UUID.randomUUID().toString().replace("-", ""); filename = uuid + "_" + filename; // 创建客户端的对象 Client client = Client.create();// 需要对文件名进行URL编码 若直接中文或空格上传会报错 filename = URLEncoder.encode(filename, "utf-8"); // 和图片服务器进行连接 WebResource webResource = client.resource(path + filename); // 上传文件 webResource.put(upload.getBytes()); return "success"; }关于报错 409可能原因是编译好的web目录下没有相应的例如以上的uploads文件夹,你项目的web目录即使有ploads文件夹文件夹但没一个文件,编译好后会自动忽略创建该目录,可在源码web目录文件夹内放任意文件即可。 403可能是web.xml未按上述配置写入权限,另外如果以上代码文件名未URL编码,中文文件名文件上传亦会产生403错误。文件上传注意事项 1、为保证服务器安全,上传文件应该放在外界无法直接访问的目录下,比如放于WEB-INF目录下。 2、为防止文件覆盖的现象发生,要为上传文件产生一个唯一的文件名。 3、为防止一个目录下面出现太多文件,要使用hash算法打散存储。 4、要限制上传文件的最大值。 5、要限制上传文件的类型,在收到上传文件名时,判断后缀名是否合法。
SpringMVC中的转换器表单提交的任何数据类型全部都是字符串类型,但是后台定义接收类型是Integer类型,数据也可以封装上,说明 Spring框架内部会默认进行数据类型转换。自定义类型转换器已知有自带的类型转换器,但在特殊情况下可能并不能满足需要,那如何自定义使用类型转换器呢?例如,前台输入2019/08/08在后端可以被Date接收,但是前台传的是2019-08-08怎么办,直接写会报错,转换器代码如下:import org.springframework.core.convert.converter.Converter;import java.text.DateFormat;import java.text.SimpleDateFormat;import java.util.Date;/** * 自定义日期转换 Converter中泛型第一个指转换的原类型,第二个是目标转换类型 */public class StringToDateConverter implements Converter<String, Date> { /** * 进行类型转换的方法 */ @Override public Date convert(String source) {// 判断 source其实就是值SpringMVC传来的值 if(source == null) {// 运行时异常 运行出错停止运行 throw new RuntimeException("参数不能为空"); }try { DateFormat df = new SimpleDateFormat("yyyy-MM-dd");// 解析字符串 Date date = df.parse(source); return date; } catch (Exception e) { throw new RuntimeException("类型转换错误"); } }}开始在springmvc.xml中配置自定义的转换器<!-- 注册自定义类型转换器 --><bean id="conversionService"class="org.springframework.context.support.ConversionServiceFactoryBean"> <property name="converters"> <set> <bean class="com.cway.utils.StringToDateConverter"/> </set> </property></bean><!-- 开启Spring对MVC注解的支持 增加类型转换器 --><mvc:annotation-driven conversion-service="conversionService"/>
SpringMVC拦截器SpringMVC框架中的拦截器用于对处理器进行预处理和后处理的技术。可以定义拦截器链,连接器链就是将拦截器按着一定的顺序结成一条链,在访问被拦截的方法时,拦截器链中的拦截器会按着定义的顺序执行。拦截器和过滤器的功能比较类似,有区别1. 过滤器是Servlet规范的一部分,任何框架都可以使用过滤器技术。 2. 拦截器是SpringMVC框架独有的,因此只对控制器方法产生作用。 3. 过滤器配置了/*,可以拦截任何资源,因此静态资源需要在配置中排除。springmvc.xml配置静态资源过滤<!-- location 表示路径,mapping 表示文件,**表示该目录下的文件以及子目录的文件 --><mvc:resources location="/css/" mapping="/css/**"/><mvc:resources location="/images/" mapping="/images/**"/><mvc:resources location="/scripts/" mapping="/javascript/**"/>拦截器只会对控制器中的方法进行拦截。拦截器也是AOP思想的一种实现方式想要自定义拦截器,需要实现HandlerInterceptor接口,然后根据需要重写里面方法。简而言之拦截器就是对控制层执行前后进行处理的工具,之前学过的@ModelAttribute注解也可以对Controller参数进行预处理,只是@ModelAttribute只是将处理好参数返给控制器了。拦截器明显可以做更多事,例如看请求中是否包含某信息,不包含则跳转到错误页面,包含则正常执行控制层。自定义拦截器步骤创建类,实现HandlerInterceptor接口,idea按ctrl+o重写需要方法,返回true放行,反之拦截。可以做登录前的验证,未登录预处理重定向或转发跳转到登录页面。public class MyInterceptor1 implements HandlerInterceptor { /** * controller方法执行前,进行拦截的方法 * return true放行 * return false拦截 * 可以使用转发或者重定向直接跳转到指定的页面。 */ public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("拦截器执行了..."); return true; }}配置springmvc.xml,以下配置了两拦截器,执行顺序,12->Controller->21->JSP->21<!-- 配置拦截器 --><mvc:interceptors> <mvc:interceptor> <!-- 哪些方法进行拦截 --> <mvc:mapping path="/user/*"/> <!-- 哪些方法不进行拦截 <mvc:exclude-mapping path=""/> --> <!-- 注册拦截器对象 --> <bean class="cn.cheng.demo1.MyInterceptor1"/> </mvc:interceptor> <mvc:interceptor> <!-- 哪些方法进行拦截 --> <mvc:mapping path="/**"/> <!-- 哪些方法不进行拦截 <mvc:exclude-mapping path=""/> --> <!-- 注册拦截器对象 --> <bean class="cn.cheng.demo1.MyInterceptor2"/> </mvc:interceptor></mvc:interceptors>preHandle方法是controller方法执行前拦截的方法可以使用request或者response跳转到指定的页面return true放行,执行下一个拦截器,如果没有拦截器,执行controller中的方法。return false不放行,不会执行controller中的方法。postHandle是controller方法执行后执行的方法,在JSP视图执行前。可以使用request或者response跳转到指定的页面如果指定了跳转的页面,那么controller方法跳转的页面将不会显示。afterHandle方法是在JSP执行后执行request或者response不能再跳转页面了
异常处理系统的 dao、service、controller 出现都通过 throws Exception 向上抛出,最后由 springmvc 前端控制器交由异常处理器进行异常处理。编写异常类public class CustomException extends Exception { private String message; public CustomException(String message) { this.message = message; } public String getMessage() { return message; }}自定义异常处理器设置如果是指定错误跳转到指定错误页面,并返回相应错误信息public class CustomExceptionResolver implements HandlerExceptionResolver { @Override public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { ex.printStackTrace(); CustomException customException = null;//如果抛出的是系统自定义异常则直接转换 if (ex instanceof CustomException) { customException = (CustomException) ex; } else {//如果抛出的不是系统自定义异常则重新构造一个系统错误异常。 customException = new CustomException("系统错误,请与系统管理 员联系!"); } ModelAndView modelAndView = new ModelAndView(); //存入错误信息 modelAndView.addObject("message", customException.getMessage()); //跳转错误页面 modelAndView.setViewName("error"); return modelAndView; }}配置异常处理器<!-- 配置异常处理器 --><bean id="sysExceptionResolver" class="com.cheng.exception.CustomExceptionResolver"/>异常处理在控制层使用在控制层的try...catch中throw new CustomException("系统错误")即可
响应数据与视图返回字符串Controller方法返回字符串可以指定逻辑视图的名称,根据视图解析器为物理视图的地址。 @RequestMapping(value="/hello") public String sayHello() { // 跳转到success页面 return "success"; }返回void1、默认会跳转到同mapping同名的页面,如@RequestMapping(value="/hello") 默认跳转到hello页面,不存在报4042、已知道Servlet 原始 API 可以作为控制器中方法的参数,可使用其做转发或重定向 @RequestMapping(value = "/initAdd") public void initAdd(HttpServletRequest request, HttpServletResponse response) throws Exception { System.out.println("请求转发或者重定向");// 请求转发 转发网址栏地址不变 页面变// request.getRequestDispatcher("/WEB-INF/pages/add.jsp").forward(request,response);// 重定向 跳转网址会产生变化// response.sendRedirect(request.getContextPath()+"/add2.jsp"); response.setCharacterEncoding("UTF-8"); response.setContentType("text/html;charset=UTF-8");// 用getWriter()直接响应数据 response.getWriter().print("你好"); return; }3、使用SpringMVC关键字进行转发与重定向如下重定向与转发不仅仅可以跳页面也能跳到其他Controller的mapping//"forward:转发的JSP路径",不走视图解析器了,所以需要编写完整的路径//转发 @RequestMapping("/delete") public String delete() throws Exception {// return "forward:/WEB-INF/pages/success.jsp"; return "forward:/user/findAll"; }//重定向 到本机不需要完整路径 @RequestMapping("/count") public String count() throws Exception { return "redirect:/add.jsp";// return "redirect:/user/findAll"; }Model与ModelAndViewModelModel作为参数可调用其addAttribute方法添加数据到request域,如下: @RequestMapping(value = "/initUpdate") public String initUpdate(Model model) {// 模拟从数据库中查询的数据 User user = new User(); user.setUsername("张三"); model.addAttribute("user", user); return "update"; }在jsp页面可通过${ requestScope }或${ user.username }调用request中内容。ModelAndViewModelAndView对象是Spring提供的一个对象,可以用来调整具体的JSP视图。它可以同时传入跳转页面名与数据对象,与上方Model功能差不多。只是Model将数据存在Model中,返回String页面名称,一般作为参数,但ModelAndView是作为返回值的。 /** * 返回ModelAndView对象 * 可以传入视图的名称(即跳转的页面),还可以传入对象。 * * @return * @throws Exception */ @RequestMapping(value = "/findAll") public ModelAndView findAll() throws Exception { ModelAndView mv = new ModelAndView();// 跳转到list.jsp的页面 mv.setViewName("list");// 模拟从数据库中查询所有的用户信息 List<User> users = new ArrayList<>(); User user1 = new User(); user1.setUsername("张三"); user1.setPassword("123"); User user2 = new User(); user2.setUsername("赵四"); user2.setPassword("456"); users.add(user1); users.add(user2);// 添加对象 mv.addObject("users", users); return mv; }JSP页面开启c标签调用<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%><%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>获取集合中值通过forEach遍历<c:forEach items="${ users }" var="user">${ user.username }</c:forEach>ResponseBody返回json@ResponseBody注解写在方法上或者方法返回的类型前,或者写在类上或者使用@RestCotroller注解public @ResponseBody Address testJson(@RequestBody String body) {}RequestBody转对象上述代码如果@RequestBody注解修饰的String变量封装成JavaBean对象public @ResponseBody Address testJson(@RequestBody Address address) {}使用jackson添加jar包即可,Springmvc 默认用 MappingJacksonHttpMessageConverter 对 json 数据进行转换<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.0</version></dependency><dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.9.0</version></dependency><dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.9.0</version></dependency>
SpringMVC简介 SpringMVC 是一种基于 Java 的实现 MVC 设计模型的请求驱动类型的轻量级 Web 框架,属于 SpringFrameWork 的后续产品,已经融合在 Spring Web Flow 里面。SpringMVC优势:1、清晰的角色划分:前端控制器(DispatcherServlet)请求到处理器映射(HandlerMapping)处理器适配器(HandlerAdapter)视图解析器(ViewResolver)处理器或页面控制器(Controller)验证器( Validator)命令对象(Command 请求参数绑定到的对象就叫命令对象)表单对象(Form Object 提供给表单展示和提交到的对象就叫表单对象)。2、分工明确,而且扩展点相当灵活,可以很容易扩展,虽然几乎不需要。3、由于命令对象就是一个 POJO,无需继承框架特定 API,可以使用命令对象直接作为业务对象。4、和 Spring 其他框架无缝集成,是其它 Web 框架所不具备的。5、可适配,通过 HandlerAdapter 可以支持任意的类作为处理器。6、可定制性,HandlerMapping、ViewResolver 等能够非常简单的定制。7、功能强大的数据验证、格式化、绑定机制。8、利用 Spring 提供的 Mock 对象能够非常简单的进行 Web 层单元测试。9、本地化、主题的解析的支持,使我们更容易进行国际化和主题的切换。10、强大的 JSP 标签库,使 JSP 编写更容易。………………还有比如RESTful风格的支持、简单的文件上传、约定大于配置的契约式编程支持、基于注解的零配置支持等等。SpringMVC配置坐标依赖 <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <spring.version>5.0.2.RELEASE</spring.version> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> <version>2.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> </dependencies>web.xml<web-app> <display-name>Archetype Created Web Application</display-name> <!-- 配置前端控制器servlet跟mapping--> <servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- 配置Servlet的初始化参数,读取springmvc的配置文件,创建spring容器 --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param> <!-- 配置servlet启动时加载对象 而不是请求时候才加载 --> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <!-- /表示所有请求都经过它--> <url-pattern>/</url-pattern> </servlet-mapping>springmvc.xml配置文件该xml文件名称可自定义,需要在web.xml中指定,详见上方web.xml配置<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"> <!-- 配置所需要的名称空间后 配置注解扫描--> <context:component-scan base-package="com.cheng"></context:component-scan> <!-- 配置视图解析器 --> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 配置视图解析器解析的前缀目录--> <property name="prefix" value="/WEB-INF/pages/"></property> <!-- 配置解析的后缀 下列也就是只解析到jsp文件--> <property name="suffix" value=".jsp"></property> </bean> <!-- 配置spring开启注解mvc的支持 该注解包含SpringMVC中的其他处理器--> <mvc:annotation-driven></mvc:annotation-driven></beans><mvc:annotation-driven />解析用 自动加载 RequestMappingHandlerMapping(处理映射器)和RequestMappingHandlerAdapter ( 处理适配器 ),如果不使用这种写法,可以使用下列配置,下载配置其实就是细化,可让你根据适合场景使用适合的处理器,而非全部加载。 <!-- Begin --> <!-- HandlerMapping --> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"></bean> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean> <!-- HandlerAdapter --> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"></bean> <bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"></bean> <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean> <!-- HadnlerExceptionResolvers --> <bean class="org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver"></bean> <bean class="org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver"></bean> <bean class="org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver"></bean> <!-- End -->小流程启动Tomcat->加载web.xml->由于配置load-on-startup启动即创建前端控制器->加载springmvc.xml->开启注解扫描->扫描@Controller注解的类创建对象前端jsp页面发请求->到前端控制器->根据@RequestMapping找具体方法执行->根据方法返回结果->根据视图解析器->查找指定的页面->Tomcat渲染页面->响应给页面常用注解@RequestMapping作用:建立请求URL与方法之间对应关系。写法:可以写在类与方法上,value值为 / 表示根目录属性:path/value 指定请求路径的url例:@RequestMapping(path ="/hello")、@RequestMapping(value="/hello")其中如果只有value一个属性的话可以省略不写,即@RequestMapping("/hello")mthod 指定该方法的请求方式@RequestMapping(value="/saveAccount",method=RequestMethod.POST)可以配置多种方式,在{}中写params 指定限制请求参数的条件RequestMapping(value="/remove",params= {"accountName","money>100"})//限制传来参数中必须有accountName、money参数,money还需要>100headers 发送的请求中必须包含的请求头RequestMapping(value="/remove",header= {"Accept"})//限制header中必须有Accept在jsp中可以采用绝对与相对URL访问mapping<a href="${pageContext.request.contextPath}/account/findAccount">绝对</a><a href="account/findAccount">相对</a>${pageContext.request.contextPath}取的是虚拟目录的名称@RequestParam与前台传递参数不一致,用它进行与形参关联,例如下列前台传的参数username,但后台必须用name时public String sayHello(@RequestParam(value="username",required=false)String name) {}@RequestBody用于获取请求体的内容(注意:get方法不适用,适用于post或ajax异步请求)required:是否必须有请求体,默认值是truepublic String sayHello(@RequestBody String body) {}@PathVariable拥有绑定url中的占位符的。例如:url中有/delete/{id},{id}就是占位符<a href="user/hello/1">入门案例</a>/*** 接收请求* @return*/@RequestMapping(path="/hello/{id}")public String sayHello(@PathVariable(value="id") String id) { System.out.println(id); return "success";}Restful风格的URL请求路径一样,可以根据不同的请求方式去执行后台的不同方法restful风格的URL优点结构清晰符合标准易于理解扩展方便@RequestHeader获取指定请求头的值public String sayHello(@RequestHeader(value="Accept") String header) {}@CookieValue获取指定cookie的名称的值@RequestMapping(path="/hello")public String sayHello(@CookieValue(value="JSESSIONID") String cookieValue) { System.out.println(cookieValue); return "success";}@ModelAttribute出现在方法上:表示当前方法会在控制器方法执行前线执行。出现在参数上:获取指定的数据给参数赋值。应用场景:当提交表单数据不是完整的实体数据时,保证没有提交的字段使用数据库原来的数据。 /** *假设User对象中有name跟password字段,前端只传了name * 要知道password 第一种在该Controller中写读数据库操作 * 第二种在@ModelAttribute修饰的方法中写数据库操作 因为它优先执行 */ @RequestMapping(path = "/updateUser") public String updateUser(User user) { System.out.println(user); return "success"; } /** * 作用在方法,先执行 * 通过前端传的name查询password并返回给user */ @ModelAttribute public User showUser(String name) { System.out.println("showUser执行了...");// 模拟从数据库中查询对象,此处为演示直接设置对象属性 User user = new User(); user.setName("哈哈"); user.setPassword("123"); return user; }假设@ModelAttribute修饰的先行方法没返回值怎么办?可在方法参数中加合适类型Map,然后将数据库查询的对象put进去,在需要的Controller方法的参数上再加@ModelAttribute注解把值再赋给user @RequestMapping(path = "/updateUser") public String updateUser(@ModelAttribute(value = "abc") User user) { System.out.println(user); return "success"; } @ModelAttribute public void showUser(String name, Map<String, User> map) { System.out.println("showUser执行了...");// 模拟从数据库中查询对象 User user = new User(); user.setName("哈哈"); user.setPassword("123"); map.put("abc", user); }@SessionAttributes用于多次执行控制器方法间的参数共享。只能写在类上。@Controller@RequestMapping(path = "/user")@SessionAttributes(value = {"username", "password", "age"}, types = {String.class, Integer.class}) // 把数据存入到session域对象中public class HelloController { /** * 向session中存入值 * * @return */ @RequestMapping(path = "/save") public String save(Model model) { System.out.println("向session域中保存数据");// 会向Request域中添加数据// 加SessionAttributes注解会再次向Session域中 model.addAttribute("username", "root"); model.addAttribute("password", "123"); model.addAttribute("age", 20); return "success"; } /** * 从session中获取值 * * @return */ @RequestMapping(path = "/find") public String find(ModelMap modelMap) {// ModelMap是Model的实现类,可以取数据 String username = (String) modelMap.get("username"); String password = (String) modelMap.get("password"); Integer age = (Integer) modelMap.get("age"); System.out.println(username + " : " + password + " : " + age); return "success"; } /** * 清除值 * * @return */ @RequestMapping(path = "/delete") public String delete(SessionStatus status) {// 将session状态设置为完成则清除session status.setComplete(); return "success"; }}参数绑定1、传什么接收什么<a href="account/findAccount?accountId=10">查询账户</a>后端:public String findAccount(Integer accountId){}2、实体类User实体类中有name跟age属性,前台传uname、age,后台用实体类直接接收后台:public String findAccount(User user){}3、关联实体类(类中有类),例如Account类中含User类:public class Account implements Serializable{ private String username; private String password; private Double money; private User user; ... } 那它前端就是:<form action="param/saveAccount" method="post"> 姓名:<input type="text" name="username" /><br/> 密码:<input type="text" name="password" /><br/> 金额:<input type="text" name="money" /><br/> 用户姓名:<input type="text" name="user.uname" /><br/> 用户年龄:<input type="text" name="user.age" /><br/> <input type="submit" value="提交" /> </form>4、数组和集合类型参数,实体类中包含List于Map <form action="param/saveAccount" method="post"> 姓名:<input type="text" name="username" /><br/> 密码:<input type="text" name="password" /><br/> 金额:<input type="text" name="money" /><br/> 用户姓名:<input type="text" name="list[0].uname" /><br/> 用户年龄:<input type="text" name="list[0].age" /><br/> 用户姓名:<input type="text" name="map['one'].uname" /><br/> 用户年龄:<input type="text" name="map['one'].age" /><br/> <input type="submit" value="提交" /> </form>过滤器解决中文乱码Get情况下乱码web.xml中加入: <!-- 配置过滤器,解决中文乱码的问题 --> <filter> <filter-name>characterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <!-- 启动过滤器 可不加--> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>characterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>在springmvc.xml中可以配置静态资源不过滤<!-- location 表示路径,mapping 表示文件,**表示该目录下的文件以及子目录的文件 --><mvc:resources location="/css/" mapping="/css/**"/><mvc:resources location="/images/" mapping="/images/**"/><mvc:resources location="/scripts/" mapping="/javascript/**"/>Post情况下乱码tomacat 对 GET 和 POST 请求处理方式是不同的,GET 请求的编码问题,要改 tomcat 的 server.xml配置文件,如下:<Connector connectionTimeout="20000" port="8080"protocol="HTTP/1.1" redirectPort="8443"/>改为:<Connector connectionTimeout="20000" port="8080"protocol="HTTP/1.1" redirectPort="8443"useBodyEncodingForURI="true"/>如果遇到 ajax 请求仍然乱码,请把:useBodyEncodingForURI="true"改为 URIEncoding="UTF-8"HiddentHttpMethodFilter由于浏览器 form 表单只支持 GET 与 POST 请求,而 DELETE、PUT 等 method 并不支持,Spring3.0 添加了一个过滤器,可以将浏览器请求改为指定的请求方式,发送给我们的控制器方法,使得支持 GET、POST、PUT 与 DELETE 请求。使用方法:第一步:在 web.xml 中配置该过滤器。第二步:请求方式必须使用 post 请求。第三步:按照要求提供_method 请求参数,该参数的取值就是我们需要的请求方式。 <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>此时,前端就要改成如下: <!-- 保存 --> <form action="springmvc/testRestPOST" method="post"> 用户名称:<input type="text" name="username"><br /> <!-- <input type="hidden" name="_method" value="POST"> --> <input type="submit" value="保存"> </form> <hr /> <!-- 更新 --> <form action="springmvc/testRestPUT/1" method="post"> 用户名称:<input type="text" name="username"><br /> <input type="hidden" name="_method" value="PUT"> <input type="submit" value="更新"> </form>说白了就是在表单中加入了<input type="hidden" name="_method" value="PUT">持续更新中……
SpringMVC 直接返回字符串时,中文乱码出现问号(?)的问题,下列是各种解决方案:通过配置spring-mvc.xml//-- 在annotation-driven中添加converter<mvc:annotation-driven> <mvc:message-converters> <bean class="org.springframework.http.converter.StringHttpMessageConverter"> <constructor-arg ref="utf8Charset" /> </bean> </mvc:message-converters></mvc:annotation-driven><bean id="utf8Charset" class="java.nio.charset.Charset" factory-method="forName"> <constructor-arg value="UTF-8" /></bean>或者<mvc:annotation-driven > <!-- 消息转换器 --> <mvc:message-converters register-defaults="true"> <bean class="org.springframework.http.converter.StringHttpMessageConverter"> <property name="supportedMediaTypes" value="text/html;charset=UTF-8"/> </bean> </mvc:message-converters> </mvc:annotation-driven>或者<mvc:annotation-driven> <mvc:message-converters register-defaults="true"> <bean class="org.springframework.http.converter.StringHttpMessageConverter"> <property name="supportedMediaTypes"> <list> <value>text/html;charset=UTF-8</value> <value>application/json;charset=UTF-8</value> <value>text/plain;charset=UTF-8</value> <value>application/xml;charset=UTF-8</value> </list> </property> </bean> </mvc:message-converters></mvc:annotation-driven>或者<mvc:annotation-driven><mvc:message-converters register-defaults="true"> <bean class="cn.dubby.what.util.MyStringHttpMessageConverter"/></mvc:annotation-driven>在requestMapping中设置下编码即在RequestMapping使用(produces = “text/html; charset=utf-8”)produces 作用根据请求头中的Accept进行匹配,如请求头“Accept:text/html”时即可匹配。@RequestMapping(method = RequestMethod.POST,produces = "text/plain;charset=UTF-8")json的话produces就是(根据自己需要修改):produces = {"application/json;charset=UTF-8"}response返回页面的话可直接设置编码public static void write(HttpServletResponse response,Object o)throws Exception{ response.setContentType("text/html;charset=utf-8"); PrintWriter out=response.getWriter(); out.println(o.toString()); out.flush(); out.close();}
设置response响应信息即可(先将文件流转成byte[])@RequestMapping(value = "down1", method = RequestMethod.GET)public void downloadAllClassmate(HttpServletResponse response) throws IOException { byte[] bytes = new byte[100]; String fileName="test.pdf"; response.setContentType("application/pdf"); //设置文件格式 response.setHeader("Content-disposition", "attachment;filename=" + fileName);//设置文件名 response.setHeader("Content-Length", "102400");//设置文件大小 response.flushBuffer(); response.getOutputStream().write(bytes); //写文件到响应体重}或者采用另一种方式@RequestMapping(value = "/down2") public ResponseEntity<byte[]> pdfDownload(HttpServletRequest httpServletRequest, HttpServletResponse response) throws IOException { String path = "d:/c.pdf"; File file = new File(path); HttpHeaders httpHeaders = new HttpHeaders(); String fileName = file.getName();// 设置文件名 httpHeaders.setContentDispositionFormData("attachment", java.net.URLEncoder.encode(fileName, "UTF-8"));// 设置响应格式 httpHeaders.setContentType(MediaType.parseMediaType("application/pdf"));// 将file放在ResponseEntity中返回 return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file), httpHeaders, HttpStatus.CREATED); }以下关于Response.ContentType 详细列表不同的ContentType 会影响客户端所看到的效果.默认的ContentType为 text/html也就是网页格式.代码如:<% response.ContentType ="text/html" %> <!--#i nclude virtual="/ContentType.html" -->显示的为网页,而<% response.ContentType ="text/plain" %> <!--#i nclude virtual="/sscript/ContentType.html" -->则会显示html原代码.以下为一些常用的 ContentTypeXML<% response.ContentType ="text/xml" %>GIF images<% response.ContentType ="image/gif" %> JPEG images<% response.ContentType ="image/jpeg" %> TIFF images<% response.ContentType ="image/tiff" %> <!--#i nclude virtual="/myimage.tiff" -->MICROSOFT WORD document<% response.ContentType ="application/msword" %> <!--#i nclude virtual="/myfile.doc" -->RTF document<% response.ContentType ="application/rtf" %> <!--#i nclude virtual="/myfile.rtf" -->MICROSOFT EXCEL document<% response.ContentType ="application/x-excel" %> <!--#i nclude virtual="/myfile.xls" -->MICROSOFT POWERPOINT document<% response.ContentType ="application/ms-powerpoint" %> <!--#i nclude virtual="/myfile.pff" -->PDF document<% response.ContentType ="application/pdf" %> <!--#i nclude virtual="/myfile.pdf" -->ZIP document<% response.ContentType ="application/zip" %> <!--#i nclude virtual="/myfile.zip" -->下面是更详细的ContentType'ez' => 'application/andrew-inset', 'hqx' => 'application/mac-binhex40', 'cpt' => 'application/mac-compactpro', 'doc' => 'application/msword', 'bin' => 'application/octet-stream', 'dms' => 'application/octet-stream', 'lha' => 'application/octet-stream', 'lzh' => 'application/octet-stream', 'exe' => 'application/octet-stream', 'class' => 'application/octet-stream', 'so' => 'application/octet-stream', 'dll' => 'application/octet-stream', 'oda' => 'application/oda', 'pdf' => 'application/pdf', 'ai' => 'application/postscript', 'eps' => 'application/postscript', 'ps' => 'application/postscript', 'smi' => 'application/smil', 'smil' => 'application/smil', 'mif' => 'application/vnd.mif', 'xls' => 'application/vnd.ms-excel', 'ppt' => 'application/vnd.ms-powerpoint', 'wbxml' => 'application/vnd.wap.wbxml', 'wmlc' => 'application/vnd.wap.wmlc', 'wmlsc' => 'application/vnd.wap.wmlscriptc', 'bcpio' => 'application/x-bcpio', 'vcd' => 'application/x-cdlink', 'pgn' => 'application/x-chess-pgn', 'cpio' => 'application/x-cpio', 'csh' => 'application/x-csh', 'dcr' => 'application/x-director', 'dir' => 'application/x-director', 'dxr' => 'application/x-director', 'dvi' => 'application/x-dvi', 'spl' => 'application/x-futuresplash', 'gtar' => 'application/x-gtar', 'hdf' => 'application/x-hdf', 'js' => 'application/x-javascript', 'skp' => 'application/x-koan', 'skd' => 'application/x-koan', 'skt' => 'application/x-koan', 'skm' => 'application/x-koan', 'latex' => 'application/x-latex', 'nc' => 'application/x-netcdf', 'cdf' => 'application/x-netcdf', 'sh' => 'application/x-sh', 'shar' => 'application/x-shar', 'swf' => 'application/x-shockwave-flash', 'sit' => 'application/x-stuffit', 'sv4cpio' => 'application/x-sv4cpio', 'sv4crc' => 'application/x-sv4crc', 'tar' => 'application/x-tar', 'tcl' => 'application/x-tcl', 'tex' => 'application/x-tex', 'texinfo' => 'application/x-texinfo', 'texi' => 'application/x-texinfo', 't' => 'application/x-troff', 'tr' => 'application/x-troff', 'roff' => 'application/x-troff', 'man' => 'application/x-troff-man', 'me' => 'application/x-troff-me', 'ms' => 'application/x-troff-ms', 'ustar' => 'application/x-ustar', 'src' => 'application/x-wais-source', 'xhtml' => 'application/xhtml+xml', 'xht' => 'application/xhtml+xml', 'zip' => 'application/zip', 'au' => 'audio/basic', 'snd' => 'audio/basic', 'mid' => 'audio/midi', 'midi' => 'audio/midi', 'kar' => 'audio/midi', 'mpga' => 'audio/mpeg', 'mp2' => 'audio/mpeg', 'mp3' => 'audio/mpeg', 'aif' => 'audio/x-aiff', 'aiff' => 'audio/x-aiff', 'aifc' => 'audio/x-aiff', 'm3u' => 'audio/x-mpegurl', 'ram' => 'audio/x-pn-realaudio', 'rm' => 'audio/x-pn-realaudio', 'rpm' => 'audio/x-pn-realaudio-plugin', 'ra' => 'audio/x-realaudio', 'wav' => 'audio/x-wav', 'pdb' => 'chemical/x-pdb', 'xyz' => 'chemical/x-xyz', 'bmp' => 'image/bmp', 'gif' => 'image/gif', 'ief' => 'image/ief', 'jpeg' => 'image/jpeg', 'jpg' => 'image/jpeg', 'jpe' => 'image/jpeg', 'png' => 'image/png', 'tiff' => 'image/tiff', 'tif' => 'image/tiff', 'djvu' => 'image/vnd.djvu', 'djv' => 'image/vnd.djvu', 'wbmp' => 'image/vnd.wap.wbmp', 'ras' => 'image/x-cmu-raster', 'pnm' => 'image/x-portable-anymap', 'pbm' => 'image/x-portable-bitmap', 'pgm' => 'image/x-portable-graymap', 'ppm' => 'image/x-portable-pixmap', 'rgb' => 'image/x-rgb', 'xbm' => 'image/x-xbitmap', 'xpm' => 'image/x-xpixmap', 'xwd' => 'image/x-xwindowdump', 'igs' => 'model/iges', 'iges' => 'model/iges', 'msh' => 'model/mesh', 'mesh' => 'model/mesh', 'silo' => 'model/mesh', 'wrl' => 'model/vrml', 'vrml' => 'model/vrml', 'css' => 'text/css', 'html' => 'text/html', 'htm' => 'text/html', 'asc' => 'text/plain', 'txt' => 'text/plain', 'rtx' => 'text/richtext', 'rtf' => 'text/rtf', 'sgml' => 'text/sgml', 'sgm' => 'text/sgml', 'tsv' => 'text/tab-separated-values', 'wml' => 'text/vnd.wap.wml', 'wmls' => 'text/vnd.wap.wmlscript', 'etx' => 'text/x-setext', 'xsl' => 'text/xml', 'xml' => 'text/xml', 'mpeg' => 'video/mpeg', 'mpg' => 'video/mpeg', 'mpe' => 'video/mpeg', 'qt' => 'video/quicktime', 'mov' => 'video/quicktime', 'mxu' => 'video/vnd.mpegurl', 'avi' => 'video/x-msvideo', 'movie' => 'video/x-sgi-movie', 'ice' => 'x-conference/x-cooltalk'