文档版本 | 开发工具 | 测试平台 | 工程名字 | 日期 | 作者 | 备注 |
---|---|---|---|---|---|---|
V1.0 | 2016.06.15 | lutianfei | none |
国际化原理,什么是国际化 ?
Java原生国家化操作
基本名称_语言(小写)_国家(大写).properties
messages_zh_CN.properties
中国中文messages_en_US.properties
美国英文 ResourceBundle bundle = ResourceBundle.getBundle("messages", Locale.US);
struts.custom.i18n.resources=testmessages,testmessages2
<constant name="struts.custom.i18n.resources" value="message">
<constant name="struts.custom.i18n.resources" value="cn.itcast.i18n.resource.message">
ActionClassName.properties
<s:i18n name="cn.itcast.action.package"></s:i18n>
<validation.xml>
1.在action类中使用
eg :
// I18nDemo1Action.properties 中 msg=hello world
public String execute() throws Exception {
// 得到properties文件中信息.
System.out.println(this.getText("msg"));
return NONE;
}
//结果就是 hello world
<message key="名称"/>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator 1.0.3//EN" "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">
<validators>
<field name="name">
<field-validator type="requiredstring">
<message key="nameerror"></message>
</field-validator>
</field>
</validators>
//properties
//package_en_US.properties
nameerror=name required
//package_zh_CN.properties
nameerror=\u540D\u5B57\u5FC5\u987B\u5730
//package.properties
nameerror=name required
3.在jsp页面上使用
<s:text name="名称">
:这里名称
为对应的Action名称。<s:i18n name="">
来指定,会从全局配置文件中获取。包名.配置文件名称
<s:i18n name="cn.itcast.action.package">
<s:text name="nameerror"/>
</s:i18n>
<s:text name="name" /> //全局包:cn.itcast.i18n.resource
//由struts.xml中常量配置决定:
//<constant name="struts.custom.i18n.resources" value="cn.itcast.i18n.resource.message"></constant>
1.action中动态文本使用
eg :
public String execute() throws Exception {
// 得到properties文件中信息.
//System.out.println(this.getText("msg"));
//动态文本
System.out.println(this.getText("msg", new String[]{"tom"}));
return NONE;
}
//结果就是 hello world tom
<s:i18n name="cn.itcast.action.I18nDemo1Action">
<s:text name="msg">
<s:param>张三</s:param>
</s:text>
</s:i18n>
* 结果就是 hello world 张三.
AOP的底层实现就是动态代理。
拦截器采用 责任链
模式
struts2中在struts-default.xml
文件中声明了所有的拦截器。
defaultStack
这个拦截器栈。com.opensymphony.xwork2.interceptor.Interceptor
在这个接口中有三个方法 public class _MyInterceptor implements Interceptor {
public void destroy() {
}
public void init() {
System.out.println("my interceptor init");
}
public String doIntercept(ActionInvocation ai) throws Exception {
System.out.println("my interceptor 拦截。。。。。");
//return ai.invoke(); // 放行
return Action.LOGIN; //"login"
}
}
<interceptor name="my" class="cn.itcast.intercept.MyInterceptor">
</interceptor>
<interceptors>
<interceptor name="my" class="cn.itcast.intercept.MyInterceptor">
</interceptor>
</interceptors>
<interceptors>
<interceptor name="my" class="cn.itcast.intercept.MyInterceptor">
</interceptor>
<interceptor name="bookInterceptor" class="cn.itcast.intercept.BookInterceptor">
<param name="includeMethods">add,update,delete</param>
</interceptor>
<interceptor-stack name="myStack">
<interceptor-ref name="bookInterceptor"></interceptor-ref>
<interceptor-ref name="defaultStack" />
</interceptor-stack>
</interceptors>
源代码执行流程:
1.在StrutsPrepareAndExecuteFilter中查找
2.在executeAction执行过程中会访问Dispatcher类中的serviceAction,在这个方法中会创建一个
ActionProxy proxy = config.getContainer().getInstance(ActionProxyFactory.class).createActionProxy(namespace, name, method, extraContext, true, false);
这就是我们的Action的代理对象3.查看ActionInvocation,查看其实现类 DefaultActionInvocation.
if (interceptors.hasNext()) {//判断是否有下一个拦截器.
final InterceptorMapping interceptor = interceptors.next(); //得到一个拦截器
String interceptorMsg = "interceptor: " + interceptor.getName();
UtilTimerStack.push(interceptorMsg);
try {
resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this);
//调用得到的拦截器的拦截方法.将本类对象传递到了拦截器中。
}
finally {
UtilTimerStack.pop(interceptorMsg);
}
}
登录成功,将用户存储到session。
login.jsp
<body>
<s:fielderror/>
<s:actionerror/>
<form action="${pageContext.request.contextPath }/login" method="post">
username:<input type="text" name="username"><br>
password:<input type="password" name="password"><br>
<input type="submit" value="登录">
</form>
</body>
public class LoginAction extends ActionSupport implements ModelDriven<User>{
private User user = new User();
public User getModel(){
return user;
}
@Override
public String execute() throws Exception {
System.out.println("name: "+user.getUsername());
System.out.println("password: "+user.getPassword());
if("miaolu".equals(user.getUsername()) && "123".equals(user.getPassword())){
ServletActionContext.getRequest().getSession().setAttribute("user", user);
return SUCCESS;
}
else{
this.addActionError("用户名或密码错误");
return INPUT;
}
}
}
<body>
<a href="${pageContext.request.contextPath}/book_add">book add</a><br>
<a href="${pageContext.request.contextPath}/book_update">book update</a><br>
<a href="${pageContext.request.contextPath}/book_delete">book delete</a><br>
<a href="${pageContext.request.contextPath}/book_search">book search</a><br>
</body>
要求:对于BookAction中的add,update,delete方法要求用户必须登录后才可以访问。search无要求。
BookAction.java
public class BookAction extends ActionSupport {
public String add() throws Exception{
System.out.println("book action add");
return null;
}
public String update() throws Exception{
System.out.println("book action update");
return null;
}
public String delete() throws Exception {
System.out.println("book action delete");
return null;
}
public String search() throws Exception {
System.out.println("book action search");
return null;
}
}
怎样解决只控制action中某些方法的拦截?
MethodFilterInterceptor
BookInterceptor.java
public class BookInterceptor extends MethodFilterInterceptor {
@Override
protected String doIntercept(ActionInvocation invocation) throws Exception {
User user = (User) ServletActionContext.getRequest().getSession().getAttribute("user");
if(user == null){
BookAction action = (BookAction) invocation.getAction();
action.addActionError("权限不足,请先登录");
return Action.LOGIN;
}
return invocation.invoke();
}
}
<struts>
<package name="default" namespace="/" extends="struts-default">
<interceptors>
<interceptor name="bookInterceptor" class="test.intercept.BookInterceptor">
<param name="includeMethods">add,update,delete</param>
<param name="excludeMethods">search</param>
</interceptor>
<interceptor-stack name="myStack">
<interceptor-ref name="bookInterceptor"></interceptor-ref>
<interceptor-ref name="defaultStack"/>
</interceptor-stack>
</interceptors>
<global-results>
<result name = "login">/login.jsp</result>
</global-results>
<action name ="login" class="test.action.LoginAction">
<result name="input">/login.jsp</result>
<result>/book.jsp</result>
</action>
<action name="book_*" class="test.action.BookAction" method="{1}">
<interceptor-ref name="myStack"/>
</action>
</package>
浏览器端:
<input type="file" name="xx">
服务器端:
struts2中文件上传
commons-fileupload组件
.<interceptor name="fileUpload" class="org.apache.struts2.interceptor.FileUploadInterceptor"/>
在action中怎样处理文件上传?
<input type="file" name="upload">
在action中要有三个属性:
ContentType
FileName
在execute方法中使用commons-io包下的FileUtils完成文件复制.
FileUtils.copyFile(upload, new File("d:/upload",uploadFileName));
@Override
public String execute() throws Exception {
System.out.println("上传文件的类型:" + uploadContentType);
System.out.println("上传文件的名称:" + uploadFileName);
// 完成文件上传.
FileUtils.copyFile(upload, new File("d:/upload", uploadFileName);
return null;
}
<action name="upload" class="cn.itcast.action.UploadAction">
</action>
struts.multipart.maxSize=2097152
上传文件默认的总大小 2MB在struts.xml`中通过修改如下参数,进行修改
<constant name="struts.multipart.maxSize" value="20971520"></constant>
2.在struts2中默认使用的是commons-fileupload进行文件上传。
3.如果出现问题,需要配置input视图,在页面上可以通过<s:actionerror>
展示错误信息.
struts.messages.error.uploading=Error uploading: {0}
struts.messages.error.file.too.large=The file is to large to be uploaded: {0} "{1}" "{2}" {3}
struts.messages.error.content.type.not.allowed=Content-Type not allowed: {0} "{1}" "{2}" {3}
struts.messages.error.file.extension.not.allowed=File extension not allowed: {0} "{1}" "{2}" {3}
struts.messages.error.uploading=上传错误: {0}
struts.messages.error.file.too.large=上传文件太大: {0} "{1}" "{2}" {3}
struts.messages.error.content.type.not.allowed=上传文件的类型不允许: {0} "{1}" "{2}" {3}
struts.messages.error.file.extension.not.allowed=上传文件的后缀名不允许: {0} "{1}" "{2}" {3}
<input type=“file” name=“uploadImage”>
中name属性的值public class UploadAction extends ActionSupport {
// 在action类中需要声明三个属性
private List<File> upload;
private List<String> uploadContentType;
private List<String> uploadFileName;
@Override
public String execute() throws Exception {
for (int i = 0; i < upload.size(); i++) {
System.out.println("上传文件的类型:" + uploadContentType.get(i));
System.out.println("上传文件的名称:" + uploadFileName.get(i));
// 完成文件上传.
FileUtils.copyFile(upload.get(i), new File("d:/upload", uploadFileName.get(i)));
}
return null;
}
}
<interceptor-ref name="defaultStack">
<param name="fileUpload.allowedExtensions">txt,mp3,doc</param>
</interceptor-ref>
<action name="upload" class="cn.itcast.action.UploadAction">
<result name="input">/upload.jsp</result>
<interceptor-ref name="defaultStack">
<param name="maximumSize">2097152</param>
<param name="fileUpload.allowedExtensions">txt,mp3,doc</param>
</interceptor-ref>
</action>
过程:
struts2中文件下载
<result type="stream">
完成。<result-type name="stream" class="org.apache.struts2.dispatcher.StreamResult"/>
在StreamResult类中有三个属性: protected String contentType = "text/plain";
: 用于设置下载文件的mimeType类型 protected String contentDisposition = "inline";
: 用于设置进行下载操作以及下载文件的名称protected InputStream inputStream;
: 用于读取要下载的文件。eg:
<action name="download" class="cn.itcast.action.DownloadAction">
<result type="stream">
<param name="contentType">${contentType}</param> <!-- 调用当前action中的getContentType()方法 -->
<param name="contentDisposition">attachment;filename=${downloadFileName}</param>
<param name="inputStream">${inputStream}</param><!-- 调用当前action中的getInputStream()方法 -->
</result>
</action>
public InputStream getInputStream() throws FileNotFoundException {
FileInputStream fis = new FileInputStream("d:/upload/" + filename);
return fis;
}
<a href="${pageContext.request.contextPath}/download?filename=捕获.png">捕获.png</a>
下载报错 public InputStream getInputStream() throws FileNotFoundException,
UnsupportedEncodingException {
filename = new String(filename.getBytes("iso8859-1"), "utf-8"); // 解决中文名称乱码.
FileInputStream fis = new FileInputStream("d:/upload/" + filename);
return fis;
}
问题2:下载捕获文件时,文件名称是a.txt
struts.xml 修订:
<result type="stream">
<param name="contentType">${contentType}</param> <!-- 调用当前action中的getContentType()方法 -->
<param name="contentDisposition">attachment;filename=${downloadFileName}</param>
<param name="inputStream">${inputStream}</param><!-- 调用当前action中的getInputStream()方法 -->
</result>
// 设置下载文件mimeType类型
public String getContentType() {
String mimeType = ServletActionContext.getServletContext().getMimeType(
filename);
return mimeType;
}
// 获取下载文件名称
public String getDownloadFileName() throws UnsupportedEncodingException {
return DownloadUtils.getDownloadFileName(ServletActionContext
.getRequest().getHeader("user-agent"), filename);
}
<result type="stream">
它有缺陷 5、操作集合对象。
使用OGNL访问 对象方法 和 静态方法
<s:property value="ognl表达式" />
执行 ognl表达式 对象.方法()
—-> <s:property value="'hello,world'.length()"/>
@[类全名(包括包路径)]@[方法名]
—> <s:property value="@java.lang.String@format('您好,%s','小明')"/>
struts.ognl.allowStaticMethodAccess=true
eg : 对象调方法
public static void main(String[] args) throws OgnlException {
// ognl可以通过对象调用方法.
// System.out.println("aaa".length());
// 使用ognl来完成上面操作.
// 1.创建一个ognl上下文。
OgnlContext context = new OgnlContext();
Object obj1 = Ognl.getValue("'aaa'.length()", context.getRoot());
System.out.println(obj1);
}
public static void main(String[] args) throws OgnlException {
// ognl可以通过对象调用方法.
System.out.println(Math.max(10, 20));
System.out.println(Math.PI);
// 使用ognl来完成上面操作.
// 1.创建一个ognl上下文。
OgnlContext context = new OgnlContext();
Object obj1 = Ognl.getValue("@java.lang.Math@max(10,20)", context.getRoot());
System.out.println(obj1);
Object obj2= Ognl.getValue("@java.lang.Math@PI", context.getRoot());
System.out.println(obj2);
}
public static void main(String[] args) throws OgnlException {
// 创建一个ognl上下文
OgnlContext context = new OgnlContext(); // 本质上就是一个Map集合.
Person p = new Person();
p.setName("张三");
Dog dog = new Dog();
dog.setName("lucy");
p.setDog(dog); //张三有条狗叫lucy
context.setRoot(p);
Dog dog1 = new Dog();
dog1.setName("豆豆");
Person pp=new Person();
pp.setName("james");
dog1.setP(pp);
context.put("dog", dog1);
context.put("name", "tom");
// 使用 ognl来获取根中数据 获取根中数据,不需要加#
Object name1 = Ognl.getValue("name", context, context.getRoot());
System.out.println(name1);
// 使用ognl来获取非根中的数据 获取非根中数据,需要使用#
Object name2 = Ognl.getValue("#name", context, context.getRoot());
System.out.println(name2);
//获取出张三的的狗的名称
//张三是root中故直接指向根张三
Object name3 = Ognl.getValue("dog.name", context, context.getRoot());
System.out.println(name3);
//豆豆的主人名称
Object name4=Ognl.getValue("#dog.p.name", context, context.getRoot());
System.out.println(name4);
}
}
//运行结果:
//张三
//tom
//lucy
//james
什么是值栈 ValueStack ?
值栈的内部结构 ?
ValueStack中 存在root属性
(CompoundRoot) 、 context 属性
(OgnlContext )
context 对应Map 引入 root对象
值栈对象的创建 ,ValueStack 和 ActionContext 是什么关系 ?
获得值栈对象的两种方法
向值栈保存数据 (主要针对 root)的两种方式
<s:debug />
查看值栈的内容 在JSP中获取值栈的数据
通过下标获取root中对象
<s:property value="[0].top"/>
//取值栈顶对象直接在root中查找对象属性 (自上而下自动查找)
valueStack:<s:property value="username"/>
在OgnlContext中获取数据
request:<s:property value="#request.username"/>
session:<s:property value="#session.username"/>
application:<s:property value="#application.username"/>
attr:<s:property value="#attr.username"/>
parameters:<s:property value="#parameters.cid[0]"/>