这里一个用户对应多个用户职称附件,所有用户表和用户职称附件表是一个一对多的关系。
多的一端
(2)操作步骤:
第一步:引入struts整合json的插件包
第二步:在struts.xml中定义:
修改:
<package name="system" namespace="/system" extends="struts-default">
修改成
<package name="system" namespace="/system" extends="json-default">
在Action中添加:
<result name="findJctUnit" type="json">result>
第三步:页面使用jquery的ajax调用二级联动的js
//ajax的二级联动,使用选择的所属单位,查询该所属单位下对应的单位名称列表
function findJctUnit(o){
//货物所属单位的文本内容
var jct = $(o).find("option:selected").text();
$.post("elecUserAction_findJctUnit.do",{"jctID":jct},function(data,textStatus){
//先删除单位名称的下拉菜单,但是请选择要留下
$("#jctUnitID option").remove();
if(data!=null && data.length>0){
for(var i=0;ivar ddlCode = data[i].ddlCode;
var ddlName = data[i].ddlName;
//添加到单位名称的下拉菜单中
var $option = $("");
$option.attr("value",ddlCode);
$option.text(ddlName);
$("#jctUnitID").append($option);
}
}
});
}
第四步:在Action中定义,这里要将返回的List集合放置到栈顶,struts2将其转换成json数据:例如:
public String findJctUnit(){
//1:传递所属单位对应的名称,以名称作为条件,查询数据字典,返回List
String jctID = elecUser.getJctID();
List<ElecSystemDDL> list = elecSystemDDLService.findSystemDDLListByKeyword(jctID);
//2:将List转化成json数据,并返回到页面上
//将list压入到struts2值栈的栈顶,struts2的插件包,将结果转换成json数据
ValueStackUtils.setValueStack(list);
return "findJctUnit";
}
上面的操作,将栈顶中封装的List集合,其中List集合中的对象所有的属性全部被json化。
总结:将List中存放的对象中的所有属性全部被json化,如果想针对某个属性被json化
此时可以修改struts.xml文件:
添加:
<result name="findJctUnit" type="json">
<param name="includeProperties">\[\d+\]\.ddlCode,\[\d+\]\.ddlNameparam>
result>
(2)操作步骤:
第一步:引入插件包
第二步:在struts.xml中定义:
修改:
<package name="system" namespace="/system" extends="struts-default">
修改成
<package name="system" namespace="/system" extends="json-default">
在struts.xml中添加:
<result name="checkUser" type="json">
<param name="root">messageparam>
<param name="includeProperties">messageparam>
result>
第三步:页面的写法
/**校验登录名是否出现重复*/
function checkUser(o){
//alert(o.value);//dom的写法
//alert($(o).val());//jquery的写法
var logonName = $(o).val();
//以登录名作为查询条件,查询该登录名是否在数据库表中存在记录
$.post("elecUserAction_checkUser.do",{"logonName":logonName},function(data){
//如果栈顶是模型驱动的对象,取值的时候应该使用data.message的方式
//如果栈顶是模型驱动的对象的某个属性,取值的时候应该使用data即可
if(data==1){
$("#check").html("登录名不能为空");
o.focus();
$("#BT_Submit").attr("disabled","none");
}
else if(data==2){
$("#check").html("登录名已经存在");
$(o)[0].focus();
$("#BT_Submit").attr("disabled","none");
}
else{
$("#check").html("登录名可以使用");
$("#BT_Submit").attr("disabled","");
}
});
}
第四步:在Action类的代码中定义:将String类型的message放置到栈顶:例如
public String checkUser(){
//1:获取页面传递的登录名,以登录名作为条件,查询用户表,返回message
String logonName = elecUser.getLogonName();
/**
* 如果message==1,说明登录名为空,此时不能执行保存
如果message==2,说明登录名在数据库表中已经存在记录(list.size()>0),此时不能执行保存
如果message==3,说明登录名在数据库表中不存在记录(list.size()==0),此时可以执行保存
*/
String message = elecUserService.checkUserByLogonName(logonName);
//将标识message的值放置到栈顶的对象,返回到页面上
elecUser.setMessage(message);
return "checkUser";
}
第五步:在Service类的代码中查询message标识的值
public String checkUserByLogonName(String logonName) {
String message = "";
if(StringUtils.isNotBlank(logonName)){
String condition = " and o.logonName=?";
Object [] params = {logonName};
//查询获取用户信息
List list = elecUserDao. onditionNoPage(condition, params, null);
if(list!=null && list.size()>0){ findCollectionByC
message = "2";
}
else{
message = "3";
}
}
else{
message = "1";
}
return message;
}
if(checkNull(theForm.contactTel)){
if(!checkPhone(theForm.contactTel.value))
{
alert("请输入正确的电话号码");
theForm.contactTel.focus();
return false;
}
}
Js中定义:function checkPhone(strNumber)
{
var pattern = /(^[0-9]{3,4}\-[0-9]{3,8}$)|(^[0-9]{3,8}$)|(^\([0-9]{3,4}\)[0-9]{3,8}$)|(^0{0,1}13[0-9]{9}$)/;
if(pattern.test(strNumber))return true;
return false;
}
大家只要知道正则表达式的用法,具体校验看项目中的要求(可以通过网络查询,获取到大家想要的表达式的写法)
多文件上传的要求:
1:完成文件上传
1:将上传的文件统一放置到upload的文件夹下
2:将每天上传的文件,使用日期格式的文件夹分开,将每个业务的模块放置统一文件夹下
3:上传的文件名要指定唯一,可以使用UUID的方式,也可以使用日期作为文件名
4:封装一个文件上传的方法,该方法可以支持多文件的上传,即支持各种格式文件的上传
5:保存路径path的时候,使用相对路径进行保存,这样便于项目的可移植性
第一步:在util包下封装一个方法:
public class FileUploadUtils {
//完成文件上传,同时返回上传文件的路径path(相对路径)
/**
* 完成文件上传
1:将上传的文件统一放置到upload的文件夹下
2:将每天上传的文件,使用日期格式的文件夹分开,并使得每个业务模块用文件夹的方式分开
3:上传的文件名要指定唯一,可以使用UUID的方式,也可以使用日期作为文件名
4:封装一个文件上传的方法,该方法可以支持多文件的上传,即支持各种格式文件的上传
5:保存路径path的时候,使用相对路径进行保存,这样便于项目的可移植性
*/
public static String fileUploadReturnPath(File upload, String uploadFileName,String model) {
//获取upload的文件夹
String basepath = ServletActionContext.getServletContext().getRealPath("/upload");
//指定日期格式的文件夹(yyyy/MM/dd)
String datepath = DateUtils.dateToString(new Date());
//文件后缀
String perfix = uploadFileName.substring(uploadFileName.lastIndexOf("."));
//文件名(格式:ADFSDFSDFA@#$@#[email protected])
String filename = UUID.randomUUID().toString()+perfix;
//判断当前日期文件夹是否存在,如果不存在,创建一个日期的文件夹
String modelPath = basepath+datepath+model;
File dateFile = new File(modelPath);
if(!dateFile.exists()){
dateFile.mkdirs();
}
//目标文件
File destFile = new File(modelPath+"/"+filename);
//文件上传
upload.renameTo(destFile);
//返回相对路径
return "/upload"+ datepath+model+"/"+filename;
}
public static void main(String[] args) throws Exception {
//文件上传
//方案一:(复制,粘贴)
//源文件
File srcFile = new File("F:\\dir\\a.txt");
//目标文件
File destFile = new File("F:\\dir\\dir2xxxxxxxxxxx\\a.txt");
//FileUtils.copyFile(srcFile, destFile);
//方案二:(剪切)
boolean flag = srcFile.renameTo(destFile);
System.out.println(flag);
}
}
第二步:jsp页面的表单要求:
并且表单提交:
第三步:文件上传的要求:
在VO对象中:
//获取文件类型的upload
private File [] upload;
//文件类型
private String [] uploadContentType;
//文件名
private String [] uploadFileName;
其中upload表示页面提交的文件:
uploadContentType表示获取上传文件的类型
uploadFileName表示获取上传文件的名称
file name="upload" id="upload" cssStyle="width:450px;"> file> *
这里注意:如果是单文件上传,就是File类型的对象
如果是多文件上传,就是File类型的数组对象
页面效果:
(1)不使用struts2提供的文件下载
Action类的处理代码:
public String download() throws Exception{
//1:获取用户附件ID,查询用户附件对象,获取路径path
String id = elecUser.getFileID();
ElecUserFile elecUserFile = elecUserService.findElecUserFileByID(id);
//路径path
String path = elecUserFile.getFileURL();
//下载时,使用的文件名
String name = elecUserFile.getFileName();
//处理中文问题,或者使用:name = URLEncoder.encode(name, "UTF-8");
name = new String(name.getBytes("gbk"),"iso-8859-1");
//2:使用response对象设置文件下载的信息(头部信息,文件类型…)
response.setHeader("Content-disposition", "attachment;filename="+name+"");
response.setBufferSize(1024);
//3:使用InputStream输入流读到path路径下对应文件,将InputStream的输入流写到输出流(response对象中获取)中
InputStream in = new FileInputStream(new File(ServletActionContext.getServletContext().getRealPath("")+path));
OutputStream out = response.getOutputStream();
for(int b=-1;(b=in.read())!=-1;){
out.write(b);
}
out.close();
in.close();
return null;
}
(2)使用struts2提供的文件下载
第一步:配置struts.xml
第二步:在模型驱动的对象中,添加InputStream类型的属性,用来存放文件的输入流
其中属性名称要与struts.xml中定义的inputName的值一致。
第三步:将查询的文件输入流放置到模型驱动定义的inputStream属性中,用来输出文件。
第四步:Action类中代码:
public String download() throws Exception{
String id = elecUser.getFileID();
ElecUserFile elecUserFile = elecUserService.findElecUserFileByID(id);
//路径path
String path = elecUserFile.getFileURL();
//下载时,使用的文件名
String name = elecUserFile.getFileName();
//处理中文问题,或者使用:name = URLEncoder.encode(name, "UTF-8");
name = new String(name.getBytes("gbk"),"iso-8859-1");
request.setAttribute("filename", name);
//2:使用InputStream输入流读到path路径下对应文件
InputStream in = new FileInputStream(new File(ServletActionContext.getServletContext().getRealPath("")+path));
//将输入流压入到栈顶
elecUser.setInputStream(in);
return "fileSuccess";
}
操作步骤:
第一步:导入工具类,放置到cn.itcast.elec.util包下
第二步:在保存用户和更新用户的前添加一个方法(md5Password):
private void md5Password(ElecUser elecUser) {
//加密前
String logonPwd = elecUser.getLogonPwd();
//加密后
String md5LogonPwd = "";
if(StringUtils.isBlank(logonPwd)){
logonPwd = "123";
}
//获取加密前的密码
String password = elecUser.getPassword();
//加密前的密码与输入的密码相等:说明没有修改密码
if(StringUtils.isNotBlank(password) && password.equals(logonPwd)){
md5LogonPwd = logonPwd;
}
else{
//使用MD5进行密码加密
MD5keyBean md5keyBean = new MD5keyBean();
md5LogonPwd = md5keyBean.getkeyBeanofStr(
logonPwd);
}
//将加密后的结果放置到ElecUser对象中
elecUser.setLogonPwd(md5LogonPwd);
}
其中password属性表示在编辑用户页面(userEdit.jsp)传递的数据库中存放的密码,用来判断是否在编辑用户的时候修改了密码:添加一个隐藏域实现,隐藏域中存放页面修改之前密码的值
<s:hidden name="password" value="%{logonPwd}">s:hidden>
重点:用户管理开发,熟练使用jquery的ajax完成业务操作,文件的上传和下载
方案一:使用URL存放路径
方案二:数据库中使用Blob字段,参考:
了解知识:md5的密码加密