1. 上傳文件javascript
大部分項目避免不了要上傳文件.php
struts2提供了封閉的上傳文件的入口, 網絡上也存在大量的插件用於網頁表單中上傳文件.css
因爲本身習慣用SSH框架, 因此介紹一下struts2中文件上傳的要點.html
struts2對文件上傳的格式,及上傳文件的大小有很好的限制.前端
#Constants
#struts.locale=zh_CN
struts.i18n.encoding=UTF-8
struts.action.extension=,
struts.objectFactory=spring
struts.custom.i18n.resources=messages
#1G
struts.multipart.maxSize=1048576000
struts.ui.theme=css_xhtml
#struts.enable.SlashesInActionNames=true
struts.devMode=false
struts.i18n.reload=true
struts.configuration.xml.reload=true
struts.serve.static.browserCache=false
struts.ui.theme=simple
上傳時的頁面 DOMjava
<s:file cssClass="doc" name="documents[0].actionFile" />
這樣上傳的文件會自動map到對象的屬性上, 或者咱們使用File []fileArray來預存表單提交到action的文件隊列.git
不過經過此方法上傳的文件隊列是沒有文件類型和文件名的,且在服務器以臨時文件存在, 並且咱們仍須要對等的使用 String []fileArrayFileName來存取對應的文件名.固然還有ContentType.web
因此到了action階段, 須要再對文件進行IO重寫操做,以保證文件以正確的格式存在合適的地方.ajax
如下代碼用於讀取存文件.spring
public static JSONObject handlerFileUpload(String dir, File file, String fileName) throws IOException { JSONObject jo = new JSONObject(); String realpath = ServletActionContext.getServletContext().getRealPath( dir);//獲取根目錄+存放目錄 System.out.println("realpath: " + realpath); File doc; if (file != null) { doc = new File(realpath, fileName);//建立文件 if (!doc.exists()) { if (!doc.getParentFile().exists()) { doc.getParentFile().mkdirs();//判斷目錄 } OutputStream os = new FileOutputStream(new File(realpath, fileName)); InputStream is = new FileInputStream(file); byte[] buf = new byte[1024]; int length = 0; while (-1 != (length = is.read(buf))) { os.write(buf, 0, length);//寫文件 } is.close(); os.close(); } jo.put("size", "" + file.length() / 1000 / 1000.0);//獲取文件信息 jo.put("fileName", fileName); jo.put("type", new MimetypesFileTypeMap().getContentType(file)); } System.err.println("file:" + jo); return jo;//返回文件信息Json }
2. 上傳圖片
上傳圖片使用了最新的Ueditor的文件上傳功能, Ueditor是個強大的富文本編輯器,能夠編輯HTML或者純文本, 且能帶格式,字體,字號,表格,段落,附件,插圖,link.
文件目錄:
基本上把
WebContent/ueditor/jsp/lib
下的jar包考到項目的lib下, 就可使用啦.
不過, 若須要配置上傳的路徑, 附件, 插圖, 塗鴉, 文件, 視頻的上傳到指定路徑則須要配置一個json文件: /WebContent/ueditor/jsp/config.json
/* 上傳圖片配置項 */ "imageActionName": "uploadimage", /* 執行上傳圖片的action名稱 */ "imageFieldName": "upfile", /* 提交的圖片表單名稱 */ "imageMaxSize": 2048000, /* 上傳大小限制,單位B */ "imageAllowFiles": [".png", ".jpg", ".jpeg", ".gif", ".bmp"], /* 上傳圖片格式顯示 */ "imageCompressEnable": true, /* 是否壓縮圖片,默認是true */ "imageCompressBorder": 1600, /* 圖片壓縮最長邊限制 */ "imageInsertAlign": "none", /* 插入的圖片浮動方式 */ "imageUrlPrefix": "", /* 圖片訪問路徑前綴 */ "imagePathFormat": "/upload/image/{yyyy}{mm}{dd}/{time}{rand:6}", /* 上傳保存路徑,能夠自定義保存路徑和文件名格式 */ /* {filename} 會替換成原文件名,配置這項須要注意中文亂碼問題 */ /* {rand:6} 會替換成隨機數,後面的數字是隨機數的位數 */ /* {time} 會替換成時間戳 */ /* {yyyy} 會替換成四位年份 */ /* {yy} 會替換成兩位年份 */ /* {mm} 會替換成兩位月份 */ /* {dd} 會替換成兩位日期 */ /* {hh} 會替換成兩位小時 */ /* {ii} 會替換成兩位分鐘 */ /* {ss} 會替換成兩位秒 */ /* 非法字符 \ : * ? " < > | */ /* 具請體看線上文檔: fex.baidu.com/ueditor/#use-format_upload_filename */
須要注意的是根路徑指向的是tomcat的webapps,並非項目目錄.
頁面調用:
<script type="text/javascript" src="../ueditor/ueditor.config.js"></script> <script type="text/javascript" src="../ueditor/ueditor.all.js"></script> <script type="text/javascript" src="../ueditor/lang/en/en.js"></script> <script type="text/javascript" src="../resources/Admin/js/imageUploadModel.js"></script>
<img id="preview" alt="The picture is missing or still not upload" src="" class="bannerimg" /> <s:textfield id="picture" name="headerImg" onclick="upImage()" cssClass="scanimg input-sm" /> <button type="button" class="input-sm" href="javascript:void(0);" onclick="clearImage();">Clear Image</button>
var _editor = UE.getEditor('upload_ue'); _editor.ready(function() { // 設置編輯器不可用 // _editor.setDisabled(); 這個地方要注意 必定要屏蔽 // 隱藏編輯器,由於不會用到這個編輯器實例,因此要隱藏 _editor.hide(); // 偵聽圖片上傳 _editor.addListener('beforeinsertimage', function(t, arg) { // 將地址賦值給相應的input,只去第一張圖片的路徑 var imgs = ''; for ( var a in arg) { imgs += arg[a].src + ','; } imgs.toString().replace(/(,$)/g,'') $("#picture").attr("value", arg[0].src); // 圖片預覽 $("#preview").attr("src", arg[0].src); }) }); // 彈出圖片上傳的對話框 function upImage() { var myImage = _editor.getDialog("insertimage"); myImage.open(); } //清除圖片 function clearImage() { $("#picture").attr("value", ""); // 圖片預覽 $("#preview").attr("src", ""); } //預覽圖片功能 $(".scanimg").hover(function() { $thisImg = $(this).prev("img"); var imgObj = new Image(); $widthU = $thisImg.css('width'); $width = $widthU.substring(0, $widthU.indexOf('px')); $scanleft = $(this).position().left; $scantop = $(this).position().top; $thisImg.css({ "left" : ($scanleft + $width * 1.4) + "px", "top" : ($scantop - $width / 3) + "px" }); $thisImg.show(); }, function() { $(this).prev("img").hide(); });
.scanimg { cursor: pointer; } .scanimg:HOVER { color: red; text-decoration: underline; } .bannerimg { display: none; position: absolute; width: 200px; min-height: 50px; background-color: rgba(66,139,202,1); /* min-width: 500px; */ /* max-width: 600px; */ }
至此, 全部相關的要素準備完畢.
預覽樣式:
3. validation
表單都須要驗證,通常有三種方式來處理驗證表單的問題
$(document).ready(function() { $('#user').next().slideDown(0); validate(); }); function validate() { var rules = { email : { required : true, email : true, uniquedEmail : true }, username : { required : true, maxlength: 16 }, password : { required : true, rangelength : [ 8, 16 ] }, company : { required : true, maxlength : 16 } } formValidate.validate('myform', rules); } formValidate = { validate : function(formId, rules) { validateForm(formId, rules); } } function validateForm(formId, rules, message) { $('#' + formId) .validate( { debug : true, // 調試模式取消submit的默認提交功能 errorClass : "error-msg", // 默認爲錯誤的樣式類爲:error focusInvalid : false, // 當爲false時,驗證無效時,沒有焦點響應 onkeyup : false, submitHandler : function(form) { // 表單提交句柄,爲一回調函數,帶一個參數:form form.submit(); // 提交表單 }, rules : rules, messages : { password : { rangelength : 'The length of the password you input must be between 8 and 16 characters' }, oldPwd : { rangelength : 'The length of the password you input must be between 8 and 16 characters' }, newPwd : { rangelength : 'The length of the password you input must be between 8 and 16 characters' }, confirmPwd : { rangelength : 'The length of the password you input must be between 8 and 16 characters' } } }); } jQuery.validator.addMethod("tele", function(value, element) { var tel = /^\d{3,4}-?\d{7,9}$/; return this.optional(element) || (tel.test(value)); }, "Please write right tele number"); jQuery.validator.addMethod("uniquedEmail", function(value, element) { var dataJson = new Object(); $.ajax({ url : 'isRegEmailExist', type : 'post', data : { email : value }, async : false, // 默認爲true 異步 error : function() { dataJson.status = 502; }, success : function(data) { dataJson = JSON.parse(data); } }); return this.optional(element) || (dataJson.status == 200); }, "The email is existed, please input other one!");
<s:form action="reg" method="post" enctype="multipart/form-data" id="myform">
.error-msg { color: #ff0000; }
上述的方式在於靈活多變,不便的地方也看到了,須要調用ajax來請求服務器驗證,且不一樣的瀏覽器對ajax返回的內容有不一樣的解釋. 默認校驗規則
(1)required:true 必輸字段
(2)remote:"check.php" 使用ajax方法調用check.php驗證輸入值
(3)email:true 必須輸入正確格式的電子郵件
(4)url:true 必須輸入正確格式的網址
(5)date:true 必須輸入正確格式的日期 日期校驗ie6出錯,慎用
(6)dateISO:true 必須輸入正確格式的日期(ISO),例如:2009-06-23,1998/01/22 只驗證格式,不驗證有效性
(7)number:true 必須輸入合法的數字(負數,小數)
(8)digits:true 必須輸入整數
(9)creditcard: 必須輸入合法的信用卡號
(10)equalTo:"#field" 輸入值必須和#field相同
(11)accept: 輸入擁有合法後綴名的字符串(上傳文件的後綴)
(12)maxlength:5 輸入長度最可能是5的字符串(漢字算一個字符)
(13)minlength:10 輸入長度最小是10的字符串(漢字算一個字符)
(14)rangelength:[5,10] 輸入長度必須介於 5 和 10 之間的字符串")(漢字算一個字符)
(15)range:[5,10] 輸入值必須介於 5 和 10 之間
(16)max:5 輸入值不能大於5
(17)min:10 輸入值不能小於10
1) Action必定要繼承自ActionSupport
2) 針對某個要進行校驗的請求處理方法編寫一個 public void validateXxx()方法,在方法內部進行表單數據校驗.
3) 也可針對全部的請求處理方法編寫public void validate()方法。
4) 在校驗方法中,能夠經過addFieldError()方法來添加字段校驗錯誤消息。
5) 當校驗失敗時,Struts框架會自動跳轉到name爲input的Result頁面。在校驗失敗頁面中,可使用<s:fielderror/>來顯示錯誤消息
6) 簡單,靈活。但重用性不高。
XML配置方式校驗。在編碼方式以前被執行。
1) 針對要校驗的Action類,在同包下編寫一個名爲:Action類名-validation.xml校驗規則文件。
2) 在校驗規則文件中添加校驗規則:具體的校驗器名,參數可參看Struts2的reference或Struts2的API。
a) Field校驗:針對Action類中每一個非自定義類型的Field進行校驗的規則。
<field name="要校驗的Field名">
<field-validator type="校驗規則器名" short-circuit="是否要短路徑校驗(默認是false)">
<param name="校驗器要使用的參數名">值</param>
<message>校驗失敗時的提示消息</message>
</field-validator>
<!-- 還可添加其它的校驗規則 -->
</field>
b) 非Field校驗:針對Action類的某些Field使用OGNL表達進行組合校驗。
<validator type="fieldexpression">
<param name="fieldName">pwd</param>
<param name="fieldName">pwd2</param>
<param name="expression"><![CDATA[pwd==pwd2]]></param><!-- OGNL表達式 -->
<message>確認密碼和密碼輸入不一致</message>
</validator>
c) visitor校驗:主要是用來校驗Action類中的自定義類型Field。(針對使用模型驅動方式時)
i) 在Action類的的校驗規則文件中針對自定義類型Field使用visitor校驗規則。
<!-- 針對自定義Field使用visitor校驗 -->
<field name="user">
<field-validator type="required" short-circuit="true">
<message>用戶的信息必填</message><!-- 消息前綴 -->
</field-validator>
<field-validator type="visitor"><!-- 指定爲visitor校驗規則 -->
<param name="context">userContext</param><!-- 指定本visitor校驗的上下文名 -->
<param name="appendPrefix">true</param><!-- 是否要添加校驗失敗消息的前綴 -->
<message>用戶的</message><!-- 消息前綴 -->
</field-validator>
</field>
ii) 針對visitor的Field編寫一個校驗規則文件.文件名爲: visitor字段類型名[-visitor校驗的上下文名]-validation.xml. 例如: 本例中的文件名爲User-userContext-validation.xml
注意: 此文件要存放到visitor字段類型所在的包下.
iii) 在visitor的Field校驗規則文件中針對要校驗的Field添加校驗規則.
3) 在校驗失敗頁面(名爲input的result頁面)中,可使用<s:fielderror/>來顯示錯誤消息。
4) 默認狀況下,XML的校驗規則對Action中全部的請求處理方法生效.此時應該只針對每一個要校驗的請求處理方法指定校驗。有兩種方式:
i) 只爲Action中的指定方法指定校驗規則文件,配置文件命名爲:Action類型名-別名-validation.xml,
別名是要校驗的方法對應的Action標籤的name屬性值。
如:UserAction在struts2.xml的配置爲:
<package name="my" extends="struts-default" namespace="/">
<action name="user_*" class="com.javacrazyer.web.action.UserAction" method="{1}">
<result name="success">/info.jsp</result>
<result name="input">/user_{1}.jsp</result>
</action>
</package>
● UserAction中有registe方法和login方法,要對registe方法進行校驗,則它的校驗規則文件名爲:UserAction-user_registe-validation.xml。
● 若是使用visitor校驗器,必需指定visitor校驗的上下文名。
ii) 在校驗攔截器中指定要驗證的方法。不太實用。
<action name="user_*" class="com.javacrazyer.web.action.UserAction" method="{1}">
<result name="success">/info.jsp</result>
<result name="input">/user_{1}.jsp</result>
<interceptor-ref name="defaultStack">
<!-- 給校驗攔截器指定不進行校驗的方法列表:用逗號隔開 -->
<param name="validation.excludeMethods">*</param>
<!-- 給校驗攔截器指定要進行校驗的方法列表:用逗號隔開 -->
<param name="validation.includeMethods">regist</param>
</interceptor-ref>
</action>
5) 同時使用客戶端校驗和服務器端校驗
i) 設置<s:form>標籤的validate屬性:
false:默認值。校驗框架只執行服務器端校驗。
true:先執行客戶端校驗,而後再執行服務器端校驗。
form標籤會根據你在服務器端配置的驗證規則生成對應的JavaScript驗證代碼。
目前支持的內置校驗器:required、requiredstring、stringlength、regex validator、email、url、int、double
ii) 不太好用,不建議使用。建議使用jQuery進行頁面表單校驗。
6) 自定義校驗器:
i) 繼承自FieldValidatorSupport抽象類。重寫validate(Object obj)方法
ii) 註冊校驗器類. 在應用程序的classpath下新建一校驗器註冊文件。名爲validators.xml,內容以下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC
"-//OpenSymphony Group//XWork Validator Config 1.0//EN"
"http://www.opensymphony.com/xwork/xwork-validator-config-1.0.dtd">
<validators>
<validator name="校驗器名" class="校驗器類的全限定名"/>
</validators>
4. Annotation方式校驗: Struts2提供了註解的方式校驗
1) @Validation 指明這個類或者接口將使用基於註解的校驗。Struts2.1中已被標識爲過期。
2) @Validations() 在同一個方法上要使用多個註解校驗時。
3) @SkipValidation 指定某個方法不須要校驗。不然全部方法都會使用校驗。也能夠在檢驗攔截器中使用validateAnnotatedMethodOnly
4) 13個內置校驗器的註解版本:(注:這些註解都只能用在方法級別上) 具體參數參見Struts2的API或Reference。
@RequiredFieldValidator
@RequiredStringValidator
@StringLengthFieldValidator
@IntRangeFieldValidator
@DoubleRangeFieldValidator
@DateRangeFieldValidator
@ExpressionValidator
@FieldExpressionValidator
@RegexFieldValidator
@EmailValidator
@UrlValidator
@VisitorFieldValidator
@ConversionErrorFieldValidator
acc_registe.jsp
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> <%@ taglib uri="/struts-tags" prefix="s" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>Struts2中基於XML配置式的校驗器使用示例</title> </head> <body> <h3>XML配置式校驗器---註冊頁面</h3><hr/> <div style="color:red"><s:fielderror/></div> <form action="acc_registe.action" method="post"> <table> <tr> <td>ID</td> <td><input type="text" name="id" value="${param.id}"/></td> </tr> <tr> <td>登陸名</td> <td><input type="text" name="name" value="${param.name}"/></td> </tr> <tr> <td>密碼</td> <td><input type="password" name="pwd"/></td> </tr> <tr> <td>重複密碼</td> <td><input type="password" name="pwd2"/></td> </tr> <tr> <td>時間</td> <td><input type="text" name="registed_date" value="${param.registed_date}"/></td> </tr> <tr> <td>email</td> <td><input type="text" name="email" value="${param.email}"/></td> </tr> <tr> <td>考試成績</td> <td><input type="text" name="score" value="${param.score}"/></td> </tr> <tr> <td colspan="2"><input type="submit" value=" 提交 "/></td> </tr> </table> </form> </body> </html>
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1.7//EN" "http://struts.apache.org/dtds/struts-2.1.7.dtd"> <struts> <!-- 請求參數的編碼方式 --> <constant name="struts.i18n.encoding" value="UTF-8"/> <!-- 指定被struts2處理的請求後綴類型。多個用逗號隔開 --> <constant name="struts.action.extension" value="action,do,go,xkk"/> <!-- 當struts.xml改動後,是否從新加載。默認值爲false(生產環境下使用),開發階段最好打開 --> <constant name="struts.configuration.xml.reload" value="true"/> <!-- 是否使用struts的開發模式。開發模式會有更多的調試信息。默認值爲false(生產環境下使用),開發階段最好打開 --> <constant name="struts.devMode" value="false"/> <!-- 設置瀏覽器是否緩存靜態內容。默認值爲true(生產環境下使用),開發階段最好關閉 --> <constant name="struts.serve.static.browserCache" value="false" /> <!-- 是否容許在OGNL表達式中調用靜態方法,默認值爲false --> <constant name="struts.ognl.allowStaticMethodAccess" value="true"/> <!-- 指定由spring負責action對象的建立 <constant name="struts.objectFactory" value="spring" /> --> <!-- 是否開啓動態方法調用 --> <constant name="struts.enable.DynamicMethodInvocation" value="false"/> <package name="my" extends="struts-default" namespace="/"> <action name="acc_*" class="com.javacrazyer.web.action.AccountAction" method="{1}"> <result name="success">/info.jsp</result> <result name="input">/acc_{1}.jsp</result> </action> </package> </struts>
package com.javacrazyer.web.action; import java.util.Date; import com.opensymphony.xwork2.ActionSupport; public class AccountAction extends ActionSupport { private static final long serialVersionUID = -1418893621512812472L; private Integer id; private String name; private String pwd; private String pwd2; private Double score; private Date registed_date; private String email; public String registe() throws Exception{ System.out.println("registe-------------------"); return SUCCESS; } public String login()throws Exception{ return SUCCESS; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Double getScore() { return score; } public void setScore(Double score) { this.score = score; } public Date getRegisted_date() { return registed_date; } public void setRegisted_date(Date registedDate) { registed_date = registedDate; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getPwd() { return pwd; } public void setPwd(String pwd) { this.pwd = pwd; } public String getPwd2() { return pwd2; } public void setPwd2(String pwd2) { this.pwd2 = pwd2; } }
user_login.jsp
4. 過濾
過濾的問題源於URLEncode/URLDecode。字符在從前端到後臺, GET方式會自動將URL行Encode,這就會致使空格,加號等字符被轉碼,因此後臺須要再次解碼。不過大部分的時候,Encode後並不是必定能正確的Decode成當初的字符,因此又出現了BASE64,POST方式的代替方案。
5. 阻止瀏覽器自動填充password/username表單域
6. 富文本編輯器
7. namespace
8.表單重複提交
9. button/input/submit 提交的方式
10. struts2 Action返回result方式處理
11. 下載文件