介绍(S & T) “物业报修系统”项目里有个图片上传
的功能模块,我花了近一个晚上理解原理和写出代码。项目框架是SSH2,而上传图片模块主要涉及到Struts2
,所以我剥离Spring和Hibernate的内容,只放出Struts2的代码。
(N : 在2015年的时候,我在Android端写过一个类似的模块,但当时我的做法是调用Restful API
将图片直接上传到服务器,写的跑在客户端上,而现在写的代码跑在服务器上,两者有较大的区别)
详细步骤(A) 主要步骤分别有Struts2配置文件的修改
、编写JSP代码
、编写后台Action处理
。
Struts2配置文件的修改 首先是web.xml
,它是TomCat服务器的配置文件,为了使得网站的默认页面是上传照片页面(default_upload_pic.jsp
),必须修改它:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 <?xml version="1.0" encoding="UTF-8" ?> <web-app version ="2.5" xmlns ="http://java.sun.com/xml/ns/javaee" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" > <display-name > 邱永臣配置</display-name > <filter > <filter-name > filterDispatcher</filter-name > <filter-class > org.apache.struts2.dispatcher.FilterDispatcher</filter-class > </filter > <filter-mapping > <filter-name > filterDispatcher</filter-name > <url-pattern > /*</url-pattern > </filter-mapping > <filter > <filter-name > struts-clean</filter-name > <filter-class > org.apache.struts2.dispatcher.ActionContextCleanUp</filter-class > </filter > <filter-mapping > <filter-name > struts-clean</filter-name > <url-pattern > /*</url-pattern > </filter-mapping > <welcome-file-list > <welcome-file > default_upload_pic.jsp</welcome-file > </welcome-file-list > <context-param > <param-name > contextConfigLocation</param-name > <param-value > WEB-INF/applicationContext.xml</param-value > </context-param > <listener > <listener-class > org.springframework.web.context.ContextLoaderListener</listener-class > </listener > </web-app >
接着是struts.xml,它配置了Struts2。在一个页面被提交到服务器后,如何进行处理、由谁处理和处理之后给浏览者返回什么内容 等都由它决定。负责处理图片上传的Action是com.ilovecl.test
包中的UploadPicAction
,它决定浏览者跳转到page1.jsp
或是page2.jsp
。此外,其中还定义了文件过滤器,不允许浏览者上传过大的文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd" > <struts > <package name ="qiuyongchen" extends ="struts-default" > <action name ="uploadPic" class ="com.ilovecl.test.UploadPicAction" > <result name ="success" > /page1.jsp</result > <result name ="input" > /page2.jsp</result > <interceptor-ref name ="fileUpload" > <param name ="maximumSize" > 4096000</param > </interceptor-ref > <interceptor-ref name ="defaultStack" > </interceptor-ref > </action > </package > </struts >
JSP代码 JSP文件负责给浏览者显示内容,它提供一个文件选择框,浏览者选择图片后点击按钮便可上传(JSP是嵌入在HTML中的脚本,和javascript类似)。 在代码里,我调用了uploadPic这个action,将图片传到服务器里后,就是它负责逻辑处理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/"; %> <%@ taglib prefix="s" uri="/struts-tags"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" > <html > <head > <base href ="<%=basePath%>" > <title > My JSP 'index.jsp' starting page</title > <meta http-equiv ="pragma" content ="no-cache" > <meta http-equiv ="cache-control" content ="no-cache" > <meta http-equiv ="expires" content ="0" > <meta http-equiv ="keywords" content ="keyword1,keyword2,keyword3" > <meta http-equiv ="description" content ="This is my page" > </head > <body > ${requestScope.message} <s:form action ="uploadPic" theme ="simple" enctype ="multipart/form-data" > <table align ="center" width ="50%" border ="1" > <tr > <td > 问题描述:</td > <td > <s:textfield name ="problemDescription" > </s:textfield > </td > </tr > <tr > <td > 物业故障地点:</td > <td > <s:textfield name ="place" > </s:textfield > </td > </tr > <tr > <td > 现场照片:</td > <td id ="more" > <s:file name ="file" > </s:file > </td > </tr > <tr > <td > <s:submit value =" submit " > </s:submit > </td > <td > <s:reset value =" reset " > </s:reset > </td > </tr > </table > </s:form > </body > </html >
后台Action 负责逻辑处理的Action是UploadPicAction,它会利用JAVA的IO将图片保存在服务器网站一个名为upload的目录里:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 /** * */ package com.ilovecl.test; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.sql.Date; import java.util.ArrayList; import java.util.List; import org.apache.struts2.ServletActionContext; import com.ilovecl.myproperty.model.RepairOrder; import com.ilovecl.myproperty.service.IPostRepairOrderService; import com.ilovecl.myproperty.util.MD5; import com.opensymphony.xwork2.ActionSupport; /** * @author 邱永臣 * */ @SuppressWarnings("serial") public class UploadPicAction extends ActionSupport { private String problemDescription; // 故障物业的具体描述 private String place; // 故障物业的地点 private Date launchDate; // 保修单的上报时间 private String message; private List<File> file; // 传到服务器里来的文件 private List<String> fileFileName; // 文件名 private List<String> fileContentType; // 文件类型 private List<String> dataUrl; private IPostRepairOrderService postRepairOrderService; /* * (non-Javadoc) * * @see com.opensymphony.xwork2.ActionSupport#execute() */ @Override public String execute() throws Exception { this.message = ""; if (problemDescription.equals("")) { this.message += "问题描述为空"; return INPUT; } else if (place.equals("")) { this.message += "物业故障地点为空"; return INPUT; } else if (file == null || file.size() != 1) { this.message += "现场图片为空为空"; return INPUT; } String md5 = saveImage(); return SUCCESS; } // 将学生上传的现场图片保存下来 private String saveImage() throws IOException { String md5String = ""; dataUrl = new ArrayList<String>(); String imgpath = "upload/"; // 将文件存储在服务器中 for (int i = 0; i < file.size(); ++i) { InputStream inputStream = new FileInputStream(file.get(i)); // 获取网站根目录的绝对路径(如C:\Users\DELL\Workspaces\MyEclipse Professional // 2014\.metadata\.me_tcat\webapps\MyProperty\) String rootPath = ServletActionContext.getServletContext() .getRealPath("/"); dataUrl.add(imgpath + fileFileName.get(i)); File dest = new File(rootPath + imgpath, fileFileName.get(i)); // 得到经MD5编码后的文件名 md5String = MD5.getMD5(fileFileName.get(i)); // 利用JAVA的IO将图片存储在网站的upload目录里 OutputStream outputStream = new FileOutputStream(dest); byte[] buffer = new byte[2048]; int len = 0; while ((len = inputStream.read(buffer)) != -1) { outputStream.write(buffer, 0, len); } inputStream.close(); outputStream.close(); } return md5String; } /** * @return the problemDescription */ public String getProblemDescription() { return problemDescription; } /** * @param problemDescription * the problemDescription to set */ public void setProblemDescription(String problemDescription) { this.problemDescription = problemDescription; } /** * @return the place */ public String getPlace() { return place; } /** * @param place * the place to set */ public void setPlace(String place) { this.place = place; } /** * @return the launchDate */ public Date getLaunchDate() { return launchDate; } /** * @param launchDate * the launchDate to set */ public void setLaunchDate(Date launchDate) { this.launchDate = launchDate; } /** * @return the message */ public String getMessage() { return message; } /** * @param message * the message to set */ public void setMessage(String message) { this.message = message; } /** * @return the file */ public List<File> getFile() { return file; } /** * @param file * the file to set */ public void setFile(List<File> file) { this.file = file; } /** * @return the fileFileName */ public List<String> getFileFileName() { return fileFileName; } /** * @param fileFileName * the fileFileName to set */ public void setFileFileName(List<String> fileFileName) { this.fileFileName = fileFileName; } /** * @return the fileContentType */ public List<String> getFileContentType() { return fileContentType; } /** * @param fileContentType * the fileContentType to set */ public void setFileContentType(List<String> fileContentType) { this.fileContentType = fileContentType; } /** * @return the dataUrl */ public List<String> getDataUrl() { return dataUrl; } /** * @param dataUrl * the dataUrl to set */ public void setDataUrl(List<String> dataUrl) { this.dataUrl = dataUrl; } /** * @return the postRepairOrderService */ public IPostRepairOrderService getPostRepairOrderService() { return postRepairOrderService; } /** * @param postRepairOrderService * the postRepairOrderService to set */ public void setPostRepairOrderService( IPostRepairOrderService postRepairOrderService) { this.postRepairOrderService = postRepairOrderService; } }
结果(R) 运行网站,首页显示如下:
选择图片并上传就可以成功地传到服务器上并保存起来了。