java中的action是指什么_Struts2【开发Action】知识要点
前言
前面Struts博文基本把Struts的配置信息講解完了.....本博文主要講解Struts對(duì)數(shù)據(jù)的處理
Action開(kāi)發(fā)的三種方式
在第一次我們寫(xiě)開(kāi)發(fā)步驟的時(shí)候,我們寫(xiě)的Action是繼承著ActionSupport類(lèi)的...為啥我們繼承了ActionSupport類(lèi)呢?下面我就會(huì)講解到
繼承ActionSupport類(lèi)
我們來(lái)看一下ActionSupport干了什么:
也就是說(shuō),如果我們?cè)贏ction類(lèi)中需要用到Struts為我們提供的數(shù)據(jù)校驗(yàn)等Struts已經(jīng)幫我們實(shí)現(xiàn)的功能,我們就繼承著ActionSupport類(lèi)..
實(shí)現(xiàn)Action接口
我們?cè)賮?lái)看看Action接口干了什么:
當(dāng)然啦,ActionSuppot也繼承著Action接口,所以ActionSuppot擁有Action接口的全部功能....因此,這種開(kāi)發(fā)方式我們是比較少用的...
不繼承任何類(lèi)、不實(shí)現(xiàn)任何接口
開(kāi)發(fā)此類(lèi)的Action,它是不繼承任何類(lèi)、不實(shí)現(xiàn)任何接口的...也就是說(shuō),它就是一個(gè)普通的Java類(lèi)....
Action類(lèi)
public class PrivilegeAction {
public String login() {
System.out.println("我是普通的javaAction,不繼承任何的類(lèi)、不實(shí)現(xiàn)任何的接口");
return "success";
}
}
在配置文件中配置:
/index.jsp
效果:
小總結(jié)
如果我們使用到了Struts2一些特用的功能,我們就需要繼承ActionSupport
如果我們沒(méi)用到Struts2的特殊功能,只要平凡寫(xiě)一個(gè)Java類(lèi)行了。
大多情況下,我們還是會(huì)繼承ActionSupport的。
請(qǐng)求數(shù)據(jù)封裝
一般地,我們使用Servlet的時(shí)候都是分為幾個(gè)步驟的:
得到web層的數(shù)據(jù)、封裝數(shù)據(jù)
調(diào)用service層的邏輯業(yè)務(wù)代碼
將數(shù)據(jù)保存在域?qū)ο笾?#xff0c;跳轉(zhuǎn)到對(duì)應(yīng)的JSP頁(yè)面
現(xiàn)在問(wèn)題來(lái)了,我們自己編寫(xiě)的Action類(lèi)是沒(méi)有request、response、Session、application之類(lèi)的對(duì)象的....我們是怎么得到web層的數(shù)據(jù)、再將數(shù)據(jù)存到域?qū)ο笾械哪?#xff1f;?
前面已經(jīng)說(shuō)過(guò)了,Struts預(yù)先幫我們完成了對(duì)數(shù)據(jù)封裝的功能,它是通過(guò)params攔截器來(lái)實(shí)現(xiàn)數(shù)據(jù)封裝的
register.jsp
首先,我們填寫(xiě)表單頁(yè)面的數(shù)據(jù),請(qǐng)求Action處理數(shù)據(jù)
用戶名:
密碼:
年齡:
生日:
Action封裝基本信息
在Action設(shè)置與JSP頁(yè)面相同的屬性,并為它們編寫(xiě)setter方法
private String username;
private String psd;
private int age;
private Date birthday;
public void setUsername(String username) {
this.username = username;
}
public void setPsd(String psd) {
this.psd = psd;
}
public void setAge(int age) {
this.age = age;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
我們直接在業(yè)務(wù)方法中訪問(wèn)這些變量,看是否能得到表單的值。
Action封裝對(duì)象
一般地,我們注冊(cè)的時(shí)候,都是在Servlet上把基本信息封裝到對(duì)象上...那么在Struts怎么做呢?
創(chuàng)建一個(gè)User類(lèi),基本的信息和JSP頁(yè)面是相同的。
package qwer;
import java.util.Date;
/**
* Created by ozc on 2017/4/27.
*/
public class User {
private String username;
private String psd;
private int age;
private Date birthday;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPsd() {
return psd;
}
public void setPsd(String psd) {
this.psd = psd;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
}
在Action中定義User對(duì)象出來(lái),并給出setter和getter方法....值得注意的是:基本信息只要setter就夠了,封裝到對(duì)象的話,需要setter和getter
public class ccAction extends ActionSupport {
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public String register() {
System.out.println(user.getUsername());
System.out.println(user.getPsd());
System.out.println(user.getAge());
System.out.println(user.getBirthday());
return "success";
}
}
在JSP頁(yè)面,提交的name要寫(xiě)成user.username之類(lèi)的
用戶名:
密碼:
年齡:
生日:
得到域?qū)ο?/p>
Struts怎么把數(shù)據(jù)保存在域?qū)ο笾心?#xff1f;??Struts提供了三種方式
一、得到Servlet API
我們可以通過(guò)ServletActionContext得到Servlet API
由于每個(gè)用戶擁有一個(gè)Action對(duì)象,那么底層為了維護(hù)用戶拿到的是當(dāng)前線程的request等對(duì)象,使用ThreadLocal來(lái)維護(hù)當(dāng)前線程下的request、response等對(duì)象...
//通過(guò)ServletActionContext得到Servlet API
javax.servlet.ServletContext context = ServletActionContext.getServletContext();
HttpServletRequest request = ServletActionContext.getRequest();
HttpSession session = request.getSession();
HttpServletResponse response = ServletActionContext.getResponse();
二、ActionContext類(lèi)
我們還可以通過(guò)ActionContext類(lèi)來(lái)得到request、response、session、application被Struts封裝的Map集合
//得到ActionContext 對(duì)象
ActionContext context = ActionContext.getContext();
Map session = context.getSession();
Map application = context.getApplication();
//這是request的Map
Map request = context.getContextMap();
三、實(shí)現(xiàn)接口
當(dāng)web容器發(fā)現(xiàn)該Action實(shí)現(xiàn)了Aware接口,會(huì)把相對(duì)應(yīng)的資源通過(guò)Aware接口注射進(jìn)去,實(shí)際上就是一種IOC。
Aware實(shí)際就是一種攔截器,攔截代碼在執(zhí)行Action之前執(zhí)行、將資源注射到Action中
實(shí)現(xiàn)SessionAware, RequestAware, ApplicationAware接口,它就要在程序中實(shí)現(xiàn)三個(gè)方法:
private Map request;
private Map session;
private Map application;
@Override
public void setApplication(Map map) {
this.application = map;
}
@Override
public void setRequest(Map map) {
this.request = map;
}
@Override
public void setSession(Map map) {
this.session = map;
}
通過(guò)這些方法,我們就可以得到對(duì)應(yīng)的Map對(duì)象.....
小總結(jié)
那么,我們有三種方法可以得到Servlet對(duì)應(yīng)的對(duì)象,那么該使用哪一種呢???
分析:
第一種方法:需要導(dǎo)入Servlet的包,與Struts耦合了
第二種方法:只能在業(yè)務(wù)方法中使用ActionContext類(lèi)得到對(duì)應(yīng)的Map對(duì)象,如果有多個(gè)方法,那么每個(gè)方法都需要寫(xiě)類(lèi)似的代碼
第三種方法:可以在類(lèi)上定義成員變量,以至于整個(gè)類(lèi)都能使用。但是需要實(shí)現(xiàn)類(lèi)、實(shí)現(xiàn)對(duì)應(yīng)的方法
如果我們需要使用到對(duì)象的其他方法,類(lèi)似getContextPath()之類(lèi)的,那么只能使用第一種
如果我們就按照平常的開(kāi)發(fā),我們就使用第二種【獲取簡(jiǎn)單,沒(méi)有耦合】
至于第三種,當(dāng)我們將來(lái)可能開(kāi)發(fā)BaseAction的時(shí)候,就使用它!
日期轉(zhuǎn)換問(wèn)題
前面博文已經(jīng)講解了,Struts2為我們實(shí)現(xiàn)了數(shù)據(jù)自動(dòng)封裝...由上篇的例子我們可以看出,表單提交過(guò)去的數(shù)據(jù)全都是String類(lèi)型的,但是經(jīng)過(guò)Struts自動(dòng)封裝,就改成是JavaBean對(duì)應(yīng)成員變量的類(lèi)型了。
但是呢,日期類(lèi)型只支持是yyyy-MM-dd這種格式的,因?yàn)槲覀冊(cè)谏蟼€(gè)例子中直接使用的是Struts支持的格式,因此沒(méi)有報(bào)錯(cuò)...本篇博文就是講解Struts如何對(duì)日期類(lèi)型的格式更好地支持
當(dāng)我們使用的是yyyyMMdd這種格式的時(shí)候,我們看看Struts的自動(dòng)封裝能不能解析出相對(duì)應(yīng)的日期
直接拋出了異常
分析
那么,我們?cè)趺醋孲truts能夠支持更多的日期格式呢??比如,我想Struts在自動(dòng)封裝數(shù)據(jù)的時(shí)候支持yyyyMMdd,yyyy年MM月dd日這樣的日期格式.....
Struts提供了轉(zhuǎn)換器給我們使用,也就是,我們可以自定義轉(zhuǎn)換器,我們定義了什么格式,Struts就可以根據(jù)對(duì)應(yīng)的格式進(jìn)行自動(dòng)封裝...
當(dāng)我們寫(xiě)完自定義轉(zhuǎn)換器,是需要向Struts說(shuō)明我們寫(xiě)了,不然的話,Struts是不知道我們自定義了轉(zhuǎn)換器類(lèi)的...
也就是說(shuō),我們要想實(shí)現(xiàn)類(lèi)型轉(zhuǎn)換,需要兩步:
編寫(xiě)自定義轉(zhuǎn)換器類(lèi)
告訴Struts我們寫(xiě)了轉(zhuǎn)換器類(lèi)
自定義轉(zhuǎn)換器類(lèi)
一般地,我們想要編寫(xiě)自定義轉(zhuǎn)換器類(lèi),都是實(shí)現(xiàn)StrutsTypeConverter類(lèi)的....
/**
* Created by ozc on 2017/5/1.
* 自定義異常轉(zhuǎn)換器類(lèi)
*
* 我們要實(shí)現(xiàn)的就是:在Struts轉(zhuǎn)換的時(shí)候,
*
*/
public class MyConvter extends StrutsTypeConverter {
//需求,當(dāng)Struts自動(dòng)封裝數(shù)據(jù)時(shí),也支持yyyyMMdd,yyyy年MM月dd日等格式的支持\
SimpleDateFormat[] format = {new SimpleDateFormat("yyyy-MM-dd"), new SimpleDateFormat("yyyyMMdd"), new SimpleDateFormat("yyyy年MM月dd日")};
/**
* 把String轉(zhuǎn)換為指定的類(lèi)型 【String To Date】
*
*
* @param map
* 當(dāng)前上下文環(huán)境
* @param strings
* jsp表單提交的字符串的值
* @param aClass
* 要轉(zhuǎn)換為的目標(biāo)類(lèi)型
*/
@Override
public Object convertFromString(Map map, String[] strings, Class aClass) {
//判斷是否有值
if (strings == null) {
return null;
}
//判斷是否是日期類(lèi)型的
if (Date.class != aClass) {
return null;
}
//遍歷循環(huán)
for (SimpleDateFormat dateFormat : format) {
try {
//解析傳遞進(jìn)來(lái)的第一個(gè)就行啦
dateFormat.parse(strings[0]);
} catch (ParseException e) {
//如果格式不對(duì),那么就跳出當(dāng)前的循環(huán)
continue;
}
}
return null;
}
@Override
public String convertToString(Map map, Object o) {
return null;
}
}
告訴Struts,我寫(xiě)了轉(zhuǎn)換器類(lèi)
告訴Struts我寫(xiě)了一個(gè)轉(zhuǎn)換器類(lèi),也分兩種方式
定義了局部轉(zhuǎn)換器類(lèi),就當(dāng)前包下的Action類(lèi)有效
定義了全局轉(zhuǎn)換器類(lèi),整個(gè)項(xiàng)目有效
全局轉(zhuǎn)換器
步驟:
在src目錄下創(chuàng)建一個(gè)名為xwork-conversion.properties的文件
配置文件的內(nèi)容:需要轉(zhuǎn)換的類(lèi)類(lèi)型=轉(zhuǎn)換器類(lèi)的全名java.util.Date=qwer.MyConvter
局部轉(zhuǎn)換器類(lèi)
步驟:
在當(dāng)前的Action包下創(chuàng)建名為Action名-conversion.properties的文件
文件的內(nèi)容為:需要轉(zhuǎn)換的字段【如果是JavaBean里的字段,需要寫(xiě)上JavaBean的】=轉(zhuǎn)換器類(lèi)的全名user.birthday=qwer.MyConvter
效果
錯(cuò)誤提示頁(yè)面
當(dāng)發(fā)生了日期轉(zhuǎn)換的異常時(shí),Struts給出的頁(yè)面是這樣子的:
這個(gè)我們稱之為input視圖,我們要做的就是給出用戶更友好的提示,于是在struts.xml文件中配置:如果返回的是input視圖,那么跳轉(zhuǎn)到我們相對(duì)應(yīng)的頁(yè)面上
/error.jsp
文件上傳和下載
在講解開(kāi)山篇的時(shí)候就已經(jīng)說(shuō)了,Struts2框架封裝了文件上傳的功能........本博文主要講解怎么使用Struts框架來(lái)完成文件上傳和下載
回顧以前的文件上傳
可以使用FileUpload或者SmartUpload組件來(lái)完成文件上傳的功能。但是呢,FileUpload組件使用起來(lái)是比較麻煩的...而SmartUPload解決中文的問(wèn)題也非常麻煩
使用Struts進(jìn)行文件上傳
從要導(dǎo)入的jar包我們就可以知道:Struts內(nèi)部還是使用fileUpload上傳組件....但是它極大的簡(jiǎn)化地我們的具體操作
那我們?cè)趺从盟?#xff1f;?看下面的圖
在Action中使用在表單中定義的name,就可以獲取代表的上傳文件的File對(duì)象
在Action中使用在表單中定義的name+FileName,就得到上傳文件的名字
JSP頁(yè)面
在注冊(cè)頁(yè)面上擁有兩個(gè)上傳文件控件
Action
得到相對(duì)應(yīng)的File對(duì)象、上傳文件名稱、上傳文件的類(lèi)型
package fileupload;
import java.io.File;
/**
* Created by ozc on 2017/5/2.
*/
public class FileUploadAction {
//上傳文件對(duì)應(yīng)的File對(duì)象
private File photo;
private File photo1;
//得到上傳文件的名稱
private String photoFileName;
private String photo1FileName;
//得到上傳文件的類(lèi)型
private String photoContentType;
private String photo1ContentType;
//給出相對(duì)應(yīng)的setter
public void setPhoto(File photo) {
this.photo = photo;
}
public void setPhoto1(File photo1) {
this.photo1 = photo1;
}
public void setPhotoFileName(String photoFileName) {
this.photoFileName = photoFileName;
}
public void setPhoto1FileName(String photo1FileName) {
this.photo1FileName = photo1FileName;
}
public void setPhotoContentType(String photoContentType) {
this.photoContentType = photoContentType;
}
public void setPhoto1ContentType(String photo1ContentType) {
this.photo1ContentType = photo1ContentType;
}
public String register() {
System.out.println(photo1FileName);
System.out.println(photoFileName);
return "success";
}
}
成功得到數(shù)據(jù):
Action業(yè)務(wù)代碼:
public String register() throws IOException {
//得到上傳的路徑
String path = ServletActionContext.getServletContext().getRealPath("upload");
System.out.println(path);
//創(chuàng)建文件對(duì)象
File destFile = new File(path,photoFileName);
//調(diào)用工具類(lèi)方法,將文件拷貝過(guò)去
FileUtils.copyFile(photo, destFile);
return "success";
}
效果:
文件下載
我們以前是通過(guò)設(shè)置request消息頭來(lái)實(shí)現(xiàn)文件下載的.....那么在Struts又如何實(shí)現(xiàn)文件下載呢??
我們請(qǐng)求服務(wù)器處理都是通過(guò)Action類(lèi)來(lái)完成的,但是呢,Action類(lèi)的業(yè)務(wù)方法都是返回字符串。因此,Struts在節(jié)點(diǎn)中提供了類(lèi)型為stream的type值。通過(guò)stream來(lái)配置相對(duì)應(yīng)的信息,從而實(shí)現(xiàn)下載!
列出所有可以下載的文件
Action類(lèi)的業(yè)務(wù)方法
public class downLoadAction {
//列出所有可以下載的文件
public String list() {
//得到upload文件夾
String path = ServletActionContext.getServletContext().getRealPath("/upload");
//創(chuàng)建file對(duì)象
File file = new File(path);
//列出文件下所有的文件
File[] files = file.listFiles();
//將這些文件存到request域中
HttpServletRequest request = ServletActionContext.getRequest();
request.setAttribute("files", files);
return "list";
}
}
Struts配置文件
/list.jsp
JSP顯示頁(yè)面
對(duì)不起,沒(méi)有下載的頁(yè)面
| 編號(hào) | 文件名稱 | 操作 |
| ${file.count} | ${fn:substringAfter(fileName, "upload\\")} | 下載 |
Action代碼:
/**
* 訪問(wèn)Action的業(yè)務(wù)方法僅僅返回的是字符串。因此Struts在result節(jié)點(diǎn)提供了stream類(lèi)型的type,
* 指定了stream就代表著我這是要下載的...
*
* 既然要下載文件,那么肯定需要幾樣?xùn)|西:
* 1、文件名
* 2、代表文件的流
*/
public String downLoad() {
return "downLoad";
}
//得到要下載的文件名,Struts提供了自動(dòng)封裝的功能
private String fileName;
//如果文件名是中文的,那么需要手動(dòng)轉(zhuǎn)換,因?yàn)槌溄邮莋et方法提交
public void setFileName(String fileName) throws UnsupportedEncodingException {
fileName = new String(fileName.getBytes("ISO8859-1"), "UTF-8");
this.fileName = fileName;
System.out.println(fileName);
}
//得到代表下載文件流,該方法由Struts調(diào)用
public InputStream getAttrInputStream() {
return ServletActionContext.getServletContext().getResourceAsStream("/upload/" + fileName);
}
//下載時(shí),顯示的名稱【如果是中文,可能會(huì)亂碼,因此要URLencode】---->在Struts.xml文件中通過(guò)${}可獲取
public String getDownFileName() throws UnsupportedEncodingException {
fileName = URLEncoder.encode(fileName, "UTF-8");
return fileName;
}
Struts.xml
/list.jsp
application/octet-stream
attrInputStream
attachment;filename=${downFileName}
1024
效果
模型驅(qū)動(dòng)
什么是模型驅(qū)動(dòng)
在Struts2中模型驅(qū)動(dòng)就是用來(lái)封裝數(shù)據(jù)的..完成數(shù)據(jù)的自動(dòng)封裝.
為什么要使用模型驅(qū)動(dòng)?
我們之前就使用過(guò)Sturts2的數(shù)據(jù)自動(dòng)封裝功能,是用params攔截器完成的...既然有了params攔截器,為啥還要模型驅(qū)動(dòng)??
當(dāng)我們使用params攔截器完成數(shù)據(jù)自動(dòng)封裝的時(shí)候,如果要封裝的是JavaBean對(duì)象,那么在web表單中就必須的name寫(xiě)上javaBean.屬性名....
這樣的話,web層和Action層就耦合了...因?yàn)樵趙eb層必須要知道封裝的JavaBean對(duì)象是什么才能夠?qū)崿F(xiàn)自動(dòng)封裝!
而模型驅(qū)動(dòng)就解決了這個(gè)問(wèn)題!即時(shí)不知道Action層的JavaBean對(duì)象是什么,也能夠完成數(shù)據(jù)自動(dòng)封裝!
模型驅(qū)動(dòng)的實(shí)現(xiàn)原理
實(shí)現(xiàn)模型驅(qū)動(dòng)功能也是由攔截器完成的,我們來(lái)看看攔截器到底做了什么吧....
攔截方法的源碼是這樣的:
public String intercept(ActionInvocation invocation) throws Exception {
//得到當(dāng)前要執(zhí)行的Action對(duì)象
Object action = invocation.getAction();
//判斷該Action對(duì)象是否實(shí)現(xiàn)了ModelDriven接口
if(action instanceof ModelDriven) {
ModelDriven modelDriven = (ModelDriven)action;
//獲取值棧對(duì)象
ValueStack stack = invocation.getStack();
//得到model的對(duì)象
Object model = modelDriven.getModel();
//把對(duì)象存到值棧對(duì)象中
if(model != null) {
stack.push(model);
}
if(this.refreshModelBeforeResult) {
invocation.addPreResultListener(new ModelDrivenInterceptor.RefreshModelBeforeResult(modelDriven, model));
}
}
return invocation.invoke();
}
把model對(duì)象放到值棧對(duì)象之后,Parameters 攔截器將把表單字段映射到 ValueStack 棧的棧頂對(duì)象的各個(gè)屬性中.
也就是說(shuō),使用模型驅(qū)動(dòng)是需要配合Params攔截器完成的!
使用數(shù)據(jù)模型驅(qū)動(dòng)
實(shí)現(xiàn)ModelDriven接口
實(shí)現(xiàn)ModelDriven接口,重寫(xiě)方法....實(shí)現(xiàn)接口時(shí),要封裝的對(duì)象是什么,形參類(lèi)型就給什么
public class UserAction extends ActionSupport implements ModelDriven {
public String login() {
return SUCCESS;
}
@Override
public User getModel() {
return null;
}
}
對(duì)象實(shí)例化
public class UserAction extends ActionSupport implements ModelDriven {
//這里一定要實(shí)例化
User user = new User();
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
@Override
public User getModel() {
return user;
}
}
測(cè)試
JSP提交頁(yè)面,直接寫(xiě)上JavaBean對(duì)象的屬性就行了..不需要寫(xiě)上JavaBean對(duì)象的名稱!
| 用戶名: |
| 密碼: |
| 電話: |
| 郵箱: |
在Action業(yè)務(wù)方法中輸出User對(duì)象的數(shù)據(jù)
@Override
public String execute() throws Exception {
System.out.println(user);
return SUCCESS;
}
如果文章有錯(cuò)的地方歡迎指正,大家互相交流。習(xí)慣在微信看技術(shù)文章,想要獲取更多的Java資源的同學(xué),可以關(guān)注微信公眾號(hào):Java3y
總結(jié)
以上是生活随笔為你收集整理的java中的action是指什么_Struts2【开发Action】知识要点的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 动词ing形式的5种用法_英语语法这样学
- 下一篇: python random randin