首发日期:2018-11-01前端
【SpringMVC的配置有注解式配置的,也有XML配置的,因为如今广泛使用注解式的开发,因此这篇博文也主要讲解注解式。】java
1.创建web工程,导入依赖包:web
【这里只是一个基础的包,仅仅实现简单的springmvc功能,支持什么切面编程之类的包都没有。为何说是最基础的包,有个老哥测试过了:https://blog.csdn.net/frankcheng5143/article/details/50512340】spring
2.配置web.xml,声明springmvc核心servlet。express
<servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <!--springmvc.xml是咱们建立的springmvc核心配置文件 --> <param-value>classpath:springmvc.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>*.action</url-pattern> </servlet-mapping>
【有注解式配置的,也有XML配置的,因为如今广泛使用注解式的开发,因此这篇博文也主要讲解注解式。】编程
1.下载springjson
2.建立web工程导入依赖包:数组
3.在web.xml中配置前端控制器,同时要指定springmvc配置文件的位置spring-mvc
<!-- 配置前端控制器 --> <servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- 设置springmvc的配置文件名称 --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param> </servlet> <!-- Spring依赖核心servlet来分发请求,须要配置拦截路径来将请求先交给servlet --> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>*.action</url-pattern> </servlet-mapping>
【这里要提一下:SpringMVC也须要Spring IOC容器,但若是Spring没有初始化IOC容器,SpringMVC也会尝试去初始化IOC;若是你的功能不涉及Spring,那么你能够不初始化IOC,若是你的功能涉及到Spring,那么你应该在web.xml中加上下面的代码来提早初始化】
<!-- 利用监听器来初始化Spring工厂 --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- 配置参数,告诉核心过滤器读取哪一个文件来建立工厂 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param>
4.建立HelloController:HelloController用于处理请求
package work.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; //先用注解的方式声明是一个bean,方便springmvc管理。 @Controller public class HelloController{ //使用注解把/MySpringMVC01/hello.action请求与下面的方法对应起来 @RequestMapping("hello") public ModelAndView hello() { System.out.println("伪装在处理业务"); //返回结果,由视图解析器解析成视图 return new ModelAndView("/WEB-INF/jsp/index.jsp"); } }
5.在springmvc配置文件中配置组件扫描,这样才可以把控制器上使用注解标明的请求与控制器的映射关系告诉springmvc【这个包扫描须要context的xsd】【注意,配置文件的讲解将会在很后面讲,但事实上内容很少,在尚未讲以前,你均可以使用下面的配置文件来作练习】:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!--扫描控制器所在的包,这样才可以识别注解 --> <context:component-scan base-package="work.controller" /> <mvc:annotation-driven /> </beans>
6.测试访问:http://localhost:8080/MySpringMVC01/hello.action
上面的示例演示了请求是如何交给SpringMVC处理以及如何返回视图的。这已经演示了“请求发起-请求处理-请求返回”的步骤了。
1.使用@Controller来注解类:
package work.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; @Controller public class HelloController{ //RequestMapping负责将请求与处理方法对应起来 @RequestMapping("/hello.action") public ModelAndView hello() { System.out.println("伪装在处理业务"); //返回结果,由视图解析器解析成视图 return new ModelAndView("/WEB-INF/jsp/index.jsp"); } }
2.在配置文件中开启包扫描:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 开启组件扫描,使得spring可以识别出注解 --> <context:component-scan base-package="work.controller" /> </beans>
spring要知道请求与控制器的映射才可以把提交的请求交给对应的控制器处理
/hello.action
/hello.action
或者/hello.*.action
或者/hello/*.action
/hello.action
或者/hello.*.action
或者/hello/*.action
@Controller public class HelloController{ //如下三种方式都会把/MySpringMVC01/hello.action请求与下面的方法对应起来 // @RequestMapping("/hello") // @RequestMapping("hello") @RequestMapping("/hello.action") public ModelAndView hello() { System.out.println("伪装在处理业务"); //返回结果,由视图解析器解析成视图 return new ModelAndView("/WEB-INF/jsp/index.jsp"); } }
public ModelAndView save(HttpServletRequest request,HttpServletResponse response,HttpSession session)
,而后利用数据域对象来获取数据:String id = request.getParameter("id");
【在形参中包含的数据域对象,springmvc会帮咱们封装到形参中】@RequestMapping("login1") public ModelAndView login1(HttpServletRequest request) { System.out.println(request.getParameter("id")); return new ModelAndView("/WEB-INF/jsp/index.jsp"); }
在方法上增长参数同名形参。好比,页面中有一个name="id"的输入框提交了数据,那么能够在方法中定义一个与这个输入框提交的数值数据类型相同的、形参名与name的属性一致的形参。public ModelAndView save(Integer id)
【注意,定义了同名形参,但页面没有提交对应的表单项,这时候封装的值为null,因此若是形参的类型没法存储null则会报错】
页面表单的编写:
<form action="login2.action" method="post"> <input type="text" name="id" > <input type="submit"> </form>
控制器方法的编写:
@RequestMapping("login2") public ModelAndView login2(Integer id) {//页面表单项名称为id System.out.println(id); return new ModelAndView("/WEB-INF/jsp/index.jsp"); }
同名参数自动封装也支持POJO类中同名属性,若是把一个POJO类对象做为形参,当提交的表单项与POJO类对象的属性同名时,也会把数据封装到POJO类对象中,但要注意表单提交的name属性必需与pojo的属性名称一致。表单的name要是 pojo的属性名
,若是属性是一个对象,那么使用 pojo的内嵌对象变量名.内嵌对象的属性名
页面表单的编写:
<form action="login3.action" method="post"> <!-- 普通属性直接使用属性名 --> <input type="text" name="id" > <input type="text" name="name" > <!-- 内嵌对象的属性,用内嵌对象变量名.内嵌对象的属性名 --> <input type="text" name="account.money" > <input type="submit"> </form>
控制器方法的编写:
@RequestMapping("login3") public ModelAndView login3(User user) { System.out.println(user.getId()+"..."+user.getName()+"..."+ user.getAccount().getMoney()); return new ModelAndView("/WEB-INF/jsp/index.jsp"); }
@RequestParam:定义参数绑定规则,解决参数名与形参名不一致问题。这时候参数默认不能为空(由@RequestParam的required属性限制,required默认为true)。
// public ModelAndView login4(@RequestParam("id") Integer uid) {//这时候必需要提交上来 public ModelAndView login4(@RequestParam(value="id",required=false) Integer uid) { //把提交的表单项名为id的值存储到形参uid中 System.out.println(uid); return new ModelAndView("/WEB-INF/jsp/index.jsp"); }
页面的编写:
<form action="login5.action" method="post"> <input type="checkbox" name="courses" value="Chinese" >语文 <input type="checkbox" name="courses" value="English" >英语 <input type="checkbox" name="courses" value="Math" >数学 <input type="submit"> </form>
控制器方法的编写:
@RequestMapping("login5") public ModelAndView login5(String[] courses) { for (String course : courses) { System.out.println(course); } return new ModelAndView("/WEB-INF/jsp/index.jsp"); }
数组类型的数据封装也是能够封装到POJO类对象中的,只要遵循形参命名规则便可。
而对于非同名的多选框,但又须要出现屡次时(相似批量修改多个表单项的状况),一般使用List搭配POJO类来存储。【注意这里List封装须要把List放到一个POJO类中(或者使用json方式来传递),它不可以直接在形参中使用同名形参封装】
页面的编写:
<form action="login6.action" method="post"> 1:<input type="text" name="accounts[0].money"> 2:<input type="text" name="accounts[1].money"> 3:<input type="text" name="accounts[2].money"> <input type="submit"> </form>
控制器方法的编写:
@RequestMapping("login6") public ModelAndView login6(MContainer mcontainer) { //MContainer类没什么特别意义,它里面有List<Account> accounts。仅做演示 for (Account account : mcontainer.getAccounts()) { System.out.println(account); } return new ModelAndView("/WEB-INF/jsp/index.jsp"); }
{}
来包裹参数,而后在方法的形参中使用@PathVariable来指定形参获取的是URL中的参数。@RequestMapping("shop/{product}/{id}") public ModelAndView shopOperation(@PathVariable("product") String product,@PathVariable("id")Integer id) { System.out.println("product:"+product+" id:"+id); return new ModelAndView("/WEB-INF/jsp/index.jsp"); } //<而后访问`http://localhost:8080/项目名/shop/food/1000.action`,就能够得出product为food和id的值为1000。
利用request传递数据:在方法中添加形参HttpServletRequest request,而后在方法中调用request的API便可。
@RequestMapping("paramreturn1") public ModelAndView paramreturn1(HttpServletRequest request) { //把数据存到request域中 request.setAttribute("name", "huluwa"); return new ModelAndView("/WEB-INF/jsp/showparam.jsp"); }
经过ModelAndView传递数据:在代码中new ModelAndView()而后调用addObject方法把参数添加进去(数据会存储到request域中,在视图中能够用EL表达式${参数名}
获取)。ModelAndView还能够做为视图返回结果,调用setName方法来设置返回的视图。
@RequestMapping("paramreturn2") public ModelAndView paramreturn2() { ModelAndView mav = new ModelAndView(); String name=new String("Robert"); mav.addObject("name", name); mav.setViewName("/WEB-INF/jsp/showparam.jsp"); return mav; }
经过Model 传递数据:在方法中定义一个Model类对象的形参,利用Model类对象的addAttribute方法把参数传递给视图。(数据会存储到request域中)。
@RequestMapping("paramreturn3") public String paramreturn3(Model model) { String name=new String("Robert"); model.addAttribute("name", name); return "/WEB-INF/jsp/showparam.jsp"; }
经过ModelMap传递数据:在方法中定义一个ModelMap类对象的形参,利用ModelMap类对象的addAttribute方法把参数传递给视图。【ModelMap是Model的实现类】
@RequestMapping("paramreturn4") public String paramreturn3(ModelMap modelmap) { String name=new String("Robert"); modelmap.addAttribute("name", name); return "/WEB-INF/jsp/showparam.jsp"; }
那么,视图怎么获取返回的参数呢?
能够经过jsp标签、jstl标签、el表达式来获取。数据都存储在request域中,可使用以下的代码来获取。
<c:forEach items="${itemList }" var="item"> <tr> <td>${item.name }</td> <td>${item.price }</td> <td>${item.detail }</td> </tr> </c:forEach>
@RequestMapping的value的值还能够是一个数组,表明控制器的方法映射给多个请求,使得多个请求路径都交给同一个方法来处理。
@RequestMapping(value= {"mapping1","mapping2"}) public ModelAndView mapping1() { System.out.println("你访问了mapping1"); return new ModelAndView("/WEB-INF/jsp/index.jsp");//随意跳个页面,关键是上面的打印结果 }
@RequestMapping注解除了能够修饰方法,也能够修饰类,修饰类的时候,至关于给方法下的@RequestMapping配置的请求路径都加了一个父级目录。
@Controller @RequestMapping("map") public class MappingTest { @RequestMapping(value= {"mapping1","mapping2"}) public ModelAndView mapping1() { System.out.println("你访问了mapping1"); return new ModelAndView("/WEB-INF/jsp/index.jsp");//随意跳个页面,关键是上面的打印结果 } //如今调用方法要访问http://localhost:8080/MySpringMVC01/map/mapping1.action }
@RequestMapping还能够限定请求的方式,某些方法可能仅仅想限定POST方法来请求,那么可使用method参数来设置。若是有多种容许的请求方法,使用数组括起来。
//只容许post方式请求 @RequestMapping(value="mapping3",method=RequestMethod.POST) public ModelAndView mapping3() { System.out.println("你访问了mapping3"); return new ModelAndView("/WEB-INF/jsp/index.jsp");//随意跳个页面,关键是上面的打印结果 }
能够经过返回一个ModelAndView对象来返回视图:
手动设置视图名称:mav.setViewName("/WEB-INF/jsp/itemList.jsp");
构造函数传入视图名称:ModelAndView mav=new ModelAndView("/WEB-INF/jsp/index.jsp");
@Controller public class ViewTest { @RequestMapping(value="mapping3") public ModelAndView view1() { System.out.println("你访问了mapping3"); /*方式一,手动设置视图名称 ModelAndView mav=new ModelAndView(); mav.setViewName("/WEB-INF/jsp/index.jsp"); return mav; */ /*方式二,构造函数传入视图名称 ModelAndView mav=new ModelAndView("/WEB-INF/jsp/index.jsp"); return mav; */ return new ModelAndView("/WEB-INF/jsp/index.jsp"); } }
经过返回一个字符串来返回视图,字符串要求是视图名称字符串。
@RequestMapping(value="view2") public String view2() { System.out.println("你访问了view2"); return "/WEB-INF/jsp/index.jsp"; }
返回void,利用request和response来进行跳转视图:【request和response跳转视图是不通过视图解析器的】
经过request转发:
@RequestMapping(value="view3") public void view3(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException { System.out.println("你访问了view3"); request.getRequestDispatcher("/WEB-INF/jsp/index.jsp").forward(request, response); return; }
经过response重定向:
@RequestMapping(value="view4") public void view4(HttpServletResponse response) throws ServletException, IOException { System.out.println("你访问了view4"); response.sendRedirect("/MySpringMVC01/login.jsp");//要注意路径区别 return; }
返回以forward或redirect带头的字符串:
redirect:后面跟着的路径能够省去项目名,其余都和response.sendRedirect()
差很少;forward:后面跟着的路径与在request.getRequestDispatcher()
中填的差很少。【redirect:和forward:也能够用在ModelAndView的返回视图中】
@RequestMapping(value="view5") public String view5() { System.out.println("你访问了view5"); // return "forward:/WEB-INF/jsp/index.jsp"; return "redirect:/login.jsp";//这里能够省去项目名 }
return "forward:hello.action";
return "redirect:hello.action";
return "hello.action";
request.getRequestDispatcher("hello.action").forward(request, response);
response.sendRedirect("hello.action")
return new ModelAndView("hello.action");
题外话:重定向时的数据存储问题
按之前的来讲,当咱们使用重定向时,像request数据域中的数据,在新的视图中是获取不了的。
咱们既想实现跳转,又想保留数据,能够利用redirect:和ModelAndView,咱们在ModelAndView中绑定数据,并在视图名称前加上
redirect:
便可,这样ModelAndView中的数据仍然可以获取。
<filter> <filter-name>encoding-filter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <!-- 下面的参数是编码成什么格式,请求的数据默认是ISO-8859-1,下面的是目标字符集 --> <!-- 效果是request.setCharacterEncoding(this.encoding); --> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>encoding-filter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
response.setHeader("Content-type", "text/html;charset=UTF-8"); response.setCharacterEncoding("utf-8");
题外话:返回视图的时候,有些jsp文件的编码不是utf-8,并且也没有在代码中显式地设置字符编码,为何仍是能正确编码?
由于Spring MVC的视图解析器帮咱们解析了jsp文件的编码格式,并帮咱们在http响应信息中自动设置了响应的字符编码格式。
与applicationContext.xml的区别:springMVC.xml主要是针对SpringMVC,因此它的配置一般都是关于SpringMVC的配置,而一些例如属性注入、事务的配置都交给Spring。
只有开启了注解扫描,SpringMVC才能识别@Controller和@RequestMapping这些注解。
<context:component-scan base-package="work.controller" />
<mvc:annotation-driven />
上面这个操做会自动注册RequestMappingHandlerMapping与RequestMappingHandlerAdapter两个Bean,这两个Bean是处理器映射器和处理器适配器,若是不配置,默认状况下的使用的是旧版的处理器映射器和处理器适配器。新版的Bean增长了很多功能,包含数据绑定支持,@NumberFormatannotation支持,@DateTimeFormat支持,@Valid支持读写XML的支持(JAXB)和读写JSON的支持(默认Jackson)等功能
控制器返回结果给核心servlet,核心servlet把结果交给视图解析器来进行解析。
视图解析器负责解析视图,咱们能够给视图解析器配置一些属性,例如前缀和后缀,若是加了后缀.jsp
,那么控制器返回的结果就会加上.jsp再进行解析。【好比加了后缀.jsp
,若是返回success,那么解析结果应该是success.jsp】
<!-- 配置视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 配置视图响应的前缀 --> <property name="prefix" value="/WEB-INF/jsp/" /> <!-- 配置视图响应的后缀 --> <property name="suffix" value=".jsp" /> </bean>
配置了以后:以返回字符串方式的视图跳转为例,return "success"解析出的视图结果将是
/WEB-INF/jsp/success.jsp
1.定义一个拦截器类实现HandlerInterceptor接口中的三个方法。
public class LoginInterceptor implements HandlerInterceptor { @Override public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3) throws Exception { //注意这个方法有Exception形参 System.out.println("afterCompletion执行了"); } @Override public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3) throws Exception { //注意这个方法有ModelAndView形参 System.out.println("postHandle执行了"); } @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object arg2) throws Exception { if(request.getSession().getAttribute("loginUser")!=null) { //返回true放行,返回false不放行 return true; } response.setHeader("Content-type", "text/html;charset=UTF-8"); response.setCharacterEncoding("utf-8"); response.getWriter().println("你没有权限,请登陆"); return false; } }
2.配置拦截器
定义了拦截器以后,咱们还须要把咱们定义的拦截器告诉springmvc。能够在springmvc.xml中配置拦截器(须要注意须要引入mvc的xsd)
<!-- 开始拦截器定义,interceptors下能够定义多个拦截器 --> <mvc:interceptors> <!-- 定义一个拦截器 --> <mvc:interceptor> <!-- path是要拦截的请求,/**表明拦截全部请求(包括二级以上目录),/*表明拦截全部一级目录请求 --> <mvc:mapping path="/**"/> <!-- bean的class里面填拦截器的全限定名 --> <bean class="work.interceptor.LoginInterceptor"></bean> </mvc:interceptor> </mvc:interceptors>
有多个拦截器时,拦截器的执行按照配置顺序。
用于配置不进行拦截的请求。例如用户有多个操做,不但愿他在没有登陆的状况进行操做,但应该容许他发起登陆与注册请求,那么登陆和注册就不该该被拦截器拦截,这时候就应该使用拦截排除。
<!-- 登陆拦截器 --> <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**"/> <!-- 配置不拦截请求的地址,path里面是不拦截的请求 --> <mvc:exclude-mapping path="/user/*"/> <bean class="work.interceptor.LoginInterceptor"></bean> </mvc:interceptor> </mvc:interceptors>
<mvc:annotation-driven />
,那么你可使用@ResponseBody和@RequestBody注解来与视图进行JSON数据交互。【下面的依赖包是从SpringMVC4才开始的,旧版本的话就不是下面三个】
@RequestMapping("/getCategory.action") @ResponseBody public Category getCategory(@RequestBody Category category) { System.out.println(category); return category; }
使用postman测试的结果:
在控制器中有时候可能也会发生异常,发生异常的时候,若是不进行处理,异常会显示到页面上。因此咱们一般都须要在控制器中进行异常处理,但下面讲到的SpringMVC支持的全局异常处理器能够拦截控制器抛出的全部异常,也就是说能够在全局异常处理器中统一处理异常。
若是控制器没有处理异常,那么能够由全局异常处理器处理异常。
1.实现接口HandlerExceptionResolver并实现resolveException方法,resolveException是用来处理异常的,返回结果是一个ModelAndView,这表明了处理完异常了能够跳转到一个视图中显示异常。
public class CategoryException implements HandlerExceptionResolver { @Override public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object hanlder, Exception e) { System.out.println(e.getStackTrace()); String message="抱歉,系统发生了错误"; ModelAndView mav = new ModelAndView(); mav.addObject("message", message); mav.setViewName("/error.jsp"); return mav; } }
2.配置异常处理器
只须要把全局异常处理器配置成一个bean便可,因为继承了andlerExceptionResolver,SpringMVC很清楚它是什么东西。
<bean class="work.exception.CategoryException"></bean>
1.首先,建立自定义异常类,继承Exception,要求要有带错误信息的构造方法(这样就能构造自定义的异常信息了。)另外,最好有异常信息的getter和setter方法,这样全局异常处理器就能够经过getter来获取异常信息了,否则采用默认的异常构造方式的话还要利用e.getMessage()来获取异常。
public class MyException extends Exception { private String msg;//这是自定义的异常信息 public MyException() { super(); } public MyException(String msg) { super(); this.msg = msg; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } }
2.在控制器中抛出自定义异常。
@RequestMapping("/save.action") public ModelAndView save(Category category) throws MyException { System.out.println(category); categoryService.save(category); if(true) {//这里假设发生了异常 throw new MyException("保存商品失败!"); } return new ModelAndView("findAll.action"); }
3.修改全局处理器代码,使得可以获取自定义异常信息。
public class CategoryException implements HandlerExceptionResolver { @Override public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object hanlder, Exception e) { String message="抱歉,系统发生了错误"; //获取抛出的自定义异常信息 if(e instanceof MyException) { message=((MyException)e).getMsg();; } ModelAndView mav = new ModelAndView(); mav.addObject("message", message); mav.setViewName("/error.jsp"); return mav; } }
在开发中,或许须要上传文件,SpringMVC也提供了很方便的上传文件功能。
1.首先导入依赖包:
2.在springmvc.xml中配置多媒体解析器
<!-- 配置多媒体处理器 --> <!-- 下面的id必须是multipartResolver --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!-- 里面能够配置一系列的值,用于配置上传文件的限制 --> </bean>
3.编写测试页面:
【要加上enctype="multipart/form-data",但注意这并不会影响其余数据的封装,由于有了多媒体处理器。】
<form class="form-inline" action="save.action" method="post" enctype="multipart/form-data"> <!-- 省去其余内容 --> <div class="form-group"> <label for="pimage">商品图片</label> <input type="file" class="form-control" id="pimage" placeholder="商品图片" name="uploadFile"> </div> <div class="form-group"> <button type="submit" class="btn btn-default">提交</button> </div> </form>
4.编写文件上传代码:在形参中添加一个参数:MultipartFile uploadfile【若是是MultipartFile类的,那么上传的数据会自动封装到对象中】【要求MultipartFile形参的名字与上传项的name相同,否则须要@RequestParam强制对应】
@RequestMapping("save.action") public ModelAndView save(Product product,MultipartFile uploadFile) throws Exception { System.out.println(product); String name = UUID.randomUUID().toString(); //随机获取文件名,避免重复 String oldName = uploadFile.getOriginalFilename();//获取原文件名 System.out.println(oldName); String extName = oldName.substring(oldName.lastIndexOf("."));//获取扩展名 File file=new File("D:\\upload\\"+name+extName);//文件存储的路径 uploadFile.transferTo(file);//存储文件到指定位置 product.setPimage(name+extName); productService.save(product); ModelAndView mav= new ModelAndView(); mav.setViewName("findAll.action"); return mav; }
这里没写,准备后期有空写的内容: