目录
首发日期:2018-11-01
【springmvc的配置有注解式配置的,也有xml配置的,由于现在普遍使用注解式的开发,所以这篇博文也主要讲解注解式。】
1.建立web工程,导入依赖包:
【这里只是一个基础的包,仅仅实现简单的springmvc功能,支持什么切面编程之类的包都没有。为什么说是最基础的包,有个老哥测试过了:https://blog.csdn.net/frankcheng5143/article/details/50512340】
2.配置web.xml,声明springmvc核心servlet。
<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.下载spring
2.创建web工程导入依赖包:
3.在web.xml中配置前端控制器,同时要指定springmvc配置文件的位置
<!-- 配置前端控制器 --> <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; }
这里没写,准备后期有空写的内容:
如对本文有疑问, 点击进行留言回复!!
[杭电多校2020]第一场 1004 Distinct Sub-palindromes
Swift -- 将本地生成的UIImage进行持久化保存(存到文件中fileManager.createFile)
网友评论