MVC编程3.docx
《MVC编程3.docx》由会员分享,可在线阅读,更多相关《MVC编程3.docx(30页珍藏版)》请在冰点文库上搜索。
MVC编程3
JavaEE综合实习项目实战
项目开始及运行
1.学习使用GIT
a)下载Git,安装并配置环境变量
在D盘建立目录app,在app里打开命令行,输入:
gitclone
操作:
开始-》运行-》cmd-》D:
回车->cdapp回车->gitclone
2、学习使用Maven
1)下载apache-maven-3.3.3-bin.zip到D盘,解压缩到当前文件夹。
2)环境变量设置
a)我的电脑->右键->属性->高级->环境变量->系统变量:
新建->
变量名:
MAVEN_HOME
变量值:
D:
\apache-maven-3.3.3
点击确定。
b)系统变量内,找到Path,双击;在弹出的变量值末尾,加上;D:
\apache-maven-3.3.3\bin
c)设置JAVA_HOME;
3.等待项目下载完成,
使用cmd进入D:
\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会在服务器启动时进行初始化。
org.springframework.web.context.ContextLoaderListener
spring会读取src/main/resources/spring目录下的xml文件,对系统进行初始化。
contextConfigLocationclasspath*:
spring/applicationContext*.xml
我们把配置文件分成几类:
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("dashboard")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:
run
添加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:
PermSize=256M-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-->component-scanbase-package="com.mossle"use-default-filters="false">include-filtertype="annotation"expression="org.springframework.stereotype.Controller"/>
component-scan>
第二步,定义Controller执行后,去哪里找到页面返回给前端。
--定义JSP文件的位置-->
所有的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
user
UserBaseController
list()
对应的页面
模块
资源
操作
/webapp/content/user/user-base-list.jsp
user
user-base
list
对应的UserBaseController里的注解如下:
@Controller@RequestMapping("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()方法返回"user/user-base-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")ListselectedItem,直接把多个同名参数转换成一个列表。
如果某个参数可能不传递给后台,可以使用@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里设置。
annotation-drivenconversion-service="conversionService"/>
自己写一个DateConverter,负责把字符串转换成Date,然后把它设置到convertionService中,最后把convertionSerivice注册到mvc:
annotation-driven里,这样在类型转换时,只要遇到Date类型,就会使用DateConverter进行转换了。
DateConverter的主要代码如下所示:
publicclassDateConverterimplementsConverter{privatestaticLoggerlogger=LoggerFactory.getLogger(DateConverter.class);privateListpatterns=newArrayList();publicDateConverter(){patterns.add("yyyy-MM-dd");patterns.add("yyyy-MM-ddHH:
mm:
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(Listpatterns){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就可以支持文件上传:
maxUploadSize表示允许上传的文件最大限制,100000不到100K。
下一步就可以在方法里获取上传的文件了:
@RequestMapping("doc-info-save")publicStringsave(@ModelAttributeDocInfodocInfo,@RequestParam("attachment")MultipartFileattachment,@RequestParamMapparameterMap,RedirectAttributesredirectAttributes)throwsException{}
从MultipartFile的transferTo()方法可以把上传内容直接写入到指定文件中,非常好用。
向页面传递参数
方法操作完后,一般会从数据库中读取一些数据显示到页面上。
为了从方法向页面传递变量,首先需要在方法中传入Modelmodel变量,然后把需要传递的参数设置到Model里。
@RequestMapping("doc-info-list")publicStringlist(@ModelAttributePagepage,@RequestParamMapparameterMap,Modelmodel){ListpropertyFilters=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);return"doc/doc-info-list";}
页面里就可以通过el获取这个变量了,比如我们使用jstl循环遍历page中的数据
forEachitems="${page.result}"var="item">
但是这个方法有一个局限,如果进行了重定