MVC编程3Word格式.docx
《MVC编程3Word格式.docx》由会员分享,可在线阅读,更多相关《MVC编程3Word格式.docx(30页珍藏版)》请在冰点文库上搜索。
\app\lemon,
项目编译
mvncompile
项目打包
mvnpackage
生成独立运行包
mvnpackage-Pstandalone
使用jetty启动项目
mvnjetty:
run
启动完成后。
访问http:
//localhost:
8080/lemon
登录账号:
lingo登录密码:
1
使用Eclipse
建议使用Eclipse进行开发,利用m2eclipse插件导入pom.xml,在eclipse的官方网站看了一下http:
//eclipse.org/downloads/,eclipse-3.7(indigo)已经之后的版本都内嵌了m2eclipse插件,可以直接使用。
下面介绍的是基于eclipse-4.3(kepler)导入项目源码,并进行编译。
首先下载eclipsehttp:
//eclipse.org/downloads/packages/。
下载完成后解压,执行eclipse.exe。
在左侧功能面板点击鼠标右键,选择import。
选择导入Maven项目
选择项目目录
此时Maven会花一定时间从远程下载系统需要的依赖包,下载完成之前软件还不能运行。
我们先看看系统结构
系统结构
启动顺序
作为一个标准的J2EE应用,程序的入口在webapp/WEB-INF/web.xml里,这里的listener会在服务器启动时进行初始化。
<
listener>
<
listener-class>
org.springframework.web.context.ContextLoaderListener<
/listener-class>
/listener>
spring会读取src/main/resources/spring目录下的xml文件,对系统进行初始化。
context-param>
param-name>
contextConfigLocation<
/param-name>
param-value>
classpath*:
spring/applicationContext*.xml<
/param-value>
/context-param>
我们把配置文件分成几类:
xml
说明
applicationContext.xml
通用配置:
加载application.properties,自动扫描bean,其他初始化。
applicationContext-activiti.xml
activiti工作流。
applicationContext-bridge.xml
用户账号,多租户,用户,用户权限暴露接口的配置,包括相关的缓存。
applicationContext-cache.xml
本地缓存和远程缓存的策略。
applicationContext-filter.xml
对应web.xml中的compositeFilter,这里配置系统的Filter和Servlet。
applicationContext-hibernate.xml
数据库持久层hibernate。
applicationContext-inspketr.xml
审计日志。
(还没用到)
applicationContext-jdbc.xml
数据库连接。
applicationContext-jms.xml
异步的消息订阅与发布。
applicationContext-jmx.xml
把一些bean导出成jmx。
applicationContext-mail.xml
邮件配置。
applicationContext-scheduler.xml
基于spring的定时任务。
applicationContext-security.xml
applicationContext-security-extend.xml
权限配置。
applicationContext-service.xml
模块间交互的定制服务。
applicationContext-springmvc.xml
springmvc相关的配置。
处理请求
系统启动成功后,可以处理用户的请求,并作出相应的响应。
相关的配置都放在src/main/resources/spring/applicationContext-springmvc.xml
系统启动时,spring会自动扫描项目里所有使用@Controller标注的类,根据对应的@RequestMapping的配置,把URL映射到对应的方法上。
比如首页的/dashboard/dashboard.do,通过springmc会映射到com.mossle.dashboard.web.DashboardAction.java里的对应方法。
对应DashboardAction.java里的配置:
@Controller@RequestMapping("
dashboard"
)publicclassDashboardController{@RequestMapping("
)publicStringlist(Modelmodel){}}
系统的代码结构规范,所有springmvc对应的代码都以Controller结尾,放在web包下。
对url命名规范进行约束采用如下规则:
模块+资源+操作
比如一个管理用户的类,com.mossle.user.web.UserBaseController
user就是模块名称。
UserBaseController对应的资源名称是user-base。
比如查询用户列表的方法就对应着/user/user-base-list.do这个url。
操作后如果需要显示jsp,就返回user/user-base-list,对应applicationContext-springmvc.xml里对应的视图配置,加上/content前缀和.jsp后缀,最终就转发到/content/user/user-base-list.jsp页面。
如果操作后,需要重定向到另一个url,比如保存用户信息后,再次跳转到用户列表页面,可以使用redirect前缀,写成redirect:
/user/user-base-list.do。
运行调试
使用jetty插件
可以直接利用内嵌的jetty插件运行系统。
右键点击项目,选择“Debugas”->
“Debugconfigurations”。
Basedirectory选择Browseworkspace,并选择当前项目。
Goals填写jetty:
添加jvm参数,点击上方jre标签,在中添加-DMAVEN_OPTS=-Xms1024M-Xmx1024M-XX:
PermSize=256M-XX:
MaxPermSize=256M
配置完成后,点击底端的“debug”按钮,就开始运行了。
运行期间可以打断点对程序进行调试。
登录页乱码问题
因为使用native2ascii-maven-plugin插件对i18n国际化文件进行自动转换,而m2eclipse不支持自动执行这个插件,所以导致使用了国际化的一些页面出现了乱码。
解决方法是:
执行一次“Runas”->
“maventest”,就会执行一次native2ascii插件,将i18n国际化文件转换成正确的内容,就可以解决乱码问题了。
需要注意的是,如果你对项目进行了clean清理,那么就要重新执行一遍maventest对i18n国际化文件进行处理。
内存溢出问题
启动之后,出现OutOfMemoryError:
PermGen
设置JAVA_OPTS=-Xms1024M-Xmx1024M-XX:
MaxPermSize=256M,加大Perm内存
******************************华丽的分割线************************************
SpringMVC
概述
MVC的主要功能是分发功能,转换参数类型,再调用后面的服务,最后返回相应的结果。
请求分发是在servlet里边做的,打开src/main/resources/spring/applicationContext-filter.xml,找到里边的springmvc。
可以看到配置了所有以.do结尾的请求就会交给它处理。
(一般是把servlet配置到web.xml里,lemonOA里为了更好的配置filter和servlet,就把它们都放到xml里,通过web.xml里的CompositeFilter将请求转发给它们。
)
实际的配置还是在src/main/resources/spring/applicationContext-springmvc.xml里。
首先配置自动扫描所有配置了@Controller注解的类:
!
--自动扫描且只扫描@Controller-->
context:
component-scanbase-package="
com.mossle"
use-default-filters="
false"
>
include-filtertype="
annotation"
expression="
org.springframework.stereotype.Controller"
/>
/context:
component-scan>
第二步,定义Controller执行后,去哪里找到页面返回给前端。
--定义JSP文件的位置-->
beanclass="
org.springframework.web.servlet.view.InternalResourceViewResolver"
propertyname="
prefix"
value="
/content/"
suffix"
.jsp"
/bean>
所有的jsp页面都放在webapp/content目录下,目录结果与Controller返回的结果对应。
URL映射规则
前端用户访问的URL最终会交给后台某个Controller类的方法处理,为了保证团队开发的URL不要越来越来,需要在开发之初就制定URL和Controller方法的映射关系。
我们采用的方法,是将URL分为三段:
模块/资源-操作.do。
比如,我们实现的模块叫user,资源叫user-base,那么对应关系如下。
URL
模块
资源
操作
/user/user-base-list.do
user
user-base
list
对应的类
com.mossle.user.web.UserBaseController
UserBaseController
list()
对应的页面
/webapp/content/user/user-base-list.jsp
对应的UserBaseController里的注解如下:
user"
)publicclassUserBaseController{@RequestMapping("
user-base-list"
)
publicStringlist(@ModelAttributePagepage,@RequestParamMapparameterMap,Modelmodel){
return"
user/user-base-list"
;
}
}
综上所述,如果我们想开发一个新功能,只要进行如下几项操作:
∙在对应的包下,一般是com.mossle.{模块名}.web,创建对应的类(一般以Controller结尾)。
∙为类添加@Controller和@RequestMapping注解,RequestMapping里使用{模块名}设置它映射的URL前缀。
∙在对应的方法上使用@RequestMapping标记子路径,类上的注解和方法上的注解组合在一起,形成了完整的URL映射。
这样/user/user-base-list.do就会映射到UserController的list()方法。
∙list()方法返回"
,这个字符串,加上xml中配置的前缀和后缀就变成了"
/content/user/user-base-list.jsp"
,这就是程序处理后最终展现的页面。
数据绑定
数据绑定和类型转换,就是把请求中的参数转换成对应的变量,提供给后续的服务处理。
HTTP请求只能传递字符串类型的参数,但是后台程序需要的变量类型就会多种多样了,比如int,long甚至是javabean这种自定义类型,如果框架能帮我们自动处理这些类型转换,就再好不过了。
SpringMVC中,最常使用的参数绑定方式是@RequestParam,不管是URL上的queryParam还是POSTbody中的FormParam都可以使用这个注解获得,并且会自动根据参数的类型进行类型转换。
比如,@RequestParam("
priority"
)intpriority,就会自动从请求中获得名为priority的参数,并转换成int类型,后台方法中可以直接使用。
也可以获得一个列表,比如前台传递的参数是selectedItem=1&
selectedItem=2,可以使用@RequestParam("
selectedItem"
)List<
Long>
selectedItem,直接把多个同名参数转换成一个列表。
如果某个参数可能不传递给后台,可以使用@RequestParam(value="
id"
required=false)Integerid,那么在没有传递参数id时,就会传递null。
如果想获得请求传递的所有参数,可以使用@RequestParamMultivalueMapparameterMap,parameterMap中包含的就是请求中的所有参数了。
如果想把参数id=1&
name=Lingo的值传入对应的javabean中,也可以使用@ModelAttributeUserBaseuserBean,SpringMVC会自动根据参数名与javabean中属性名的对应关系,把参数值复制到javabean中,这在前台表单有几十个参数需要传递给后台的情况就十分有用了。
类型转换
SpringMVC虽然可以自动处理原始类型(byte,short,int,long,float,double,boolean,char),字符串String,集合以及javabean。
但是对于特殊的数据类型,还是需要特殊处理。
比如日期,前台传过来的到底是long型,还是yyyy-MM-ddHH:
mm:
ss,还是yyyy-MM-dd呢?
这就需要我们手工设置了。
对于单个参数,可以使用@DateTimeFormat(pattern="
yyyy-MM-dd"
)指定转换格式。
如果想进行全局配置,需要在xml里设置。
mvc:
annotation-drivenconversion-service="
conversionService"
beanid="
class="
org.springframework.format.support.FormattingConversionServiceFactoryBean"
converters"
list>
com.mossle.core.spring.DateConverter"
/>
/list>
/property>
自己写一个DateConverter,负责把字符串转换成Date,然后把它设置到convertionService中,最后把convertionSerivice注册到mvc:
annotation-driven里,这样在类型转换时,只要遇到Date类型,就会使用DateConverter进行转换了。
DateConverter的主要代码如下所示:
publicclassDateConverterimplementsConverter<
String,Date>
{privatestaticLoggerlogger=LoggerFactory.getLogger(DateConverter.class);
privateList<
String>
patterns=newArrayList<
();
publicDateConverter(){patterns.add("
);
patterns.add("
yyyy-MM-ddHH:
ss"
}publicDateconvert(Stringtext){if(text==null){returnnull;
}for(Stringpattern:
patterns){Datedate=tryConvert(text,pattern);
if(date!
=null){returndate;
}}returnnull;
}publicDatetryConvert(Stringtext,Stringpattern){DateFormatdateFormat=newSimpleDateFormat(pattern);
dateFormat.setLenient(false);
try{returndateFormat.parse(text);
}catch(ParseExceptionex){logger.debug(ex.getMessage(),ex);
}returnnull;
}publicvoidsetPatterns(List<
patterns){this.patterns=patterns;
}}
请求转发
如果处理完请求后,不是渲染某个页面,而是需要发送302请求,跳转到另一个URL,可以使用redirect前缀。
return"
redirect:
/user/user-base-list.do"
这样请求处理完成后,不会显示对应的渲染页面,而是会重定向到/user/user-base-list.do这个URL,由这个URL的后台页面重新渲染展示。
重定向对于希望在请求后改变url的场景非常有用,比如我们新建了一个用户,如果不进行重定向,URL就不会改变,如果用户点击了F5刷新页面,就会在发起一条请求,在后台插入一条重复的数据。
而当使用了重定向以后,URL会跳转到显示列表的页面,这时点击F5也不会造成重复操作了。
文件上传
在xml里设置了multipartResolver就可以支持文件上传:
multipartResolver"
mons.CommonsMultipartResolver"
defaultEncoding"
utf-8"
maxUploadSize"
100000"
maxUploadSize表示允许上传的文件最大限制,100000不到100K。
下一步就可以在方法里获取上传的文件了:
@RequestMapping("
doc-info-save"
)publicStringsave(@ModelAttributeDocInfodocInfo,@RequestParam("
attachment"
)MultipartFileattachment,@RequestParamMap<
String,Object>
parameterMap,RedirectAttributesredirectAttributes)throwsException{}
从MultipartFile的transferTo()方法可以把上传内容直接写入到指定文件中,非常好用。
向页面传递参数
方法操作完后,一般会从数据库中读取一些数据显示到页面上。
为了从方法向页面传递变量,首先需要在方法中传入Modelmodel变量,然后把需要传递的参数设置到Model里。
doc-info-list"
)publicStringlist(@ModelAttributePagepage,@RequestParamMap<
parameterMap,Modelmodel){List<
PropertyFilter>
propertyFilters=PropertyFilter.buildFromMap(parameterMap);
StringuserId=userConnector.findByUsername(SpringSecurityUtils.getCurrentUsername(),ScopeHolder.getUserRepoRef()).getId();
propertyFilters.add(newPropertyFilter("
EQL_userId"
userId));
page=docInfoManager.pagedQuery(page,propertyFilters);
model.addAttribute("
page"
page);
doc/doc-info-list"
页面里就可以通过el获取这个变量了,比如我们使用jstl循环遍历page中的数据
c:
forEachitems="
${page.result}"
var="
item"
但是这个方法有一个局限,如果进行了重定