天我們從源碼角度來聊聊這個話題。
理解源碼的前提是先會用,所以我們還是先來看看用法,然后再來分析源碼。
對于上傳文件的請求,SpringMVC 中目前共有兩種不同的解析方案:
StandardServletMultipartResolver 支持 Servlet3.0 中標準的文件上傳方案,使用非常簡單;CommonsMultipartResolver 則需要結合 Apache Commons fileupload 組件一起使用,這種方式兼容低版本的 Servlet。
StandardServletMultipartResolver
先來回顧下 StandardServletMultipartResolver 的用法。
使用 StandardServletMultipartResolver,可以直接通過 HttpServletRequest 自帶的 getPart 方法獲取上傳文件并保存,這是一種標準的操作方式,這種方式也不用添加任何額外的依賴,只需要確保 Servlet 的版本在 3.0 之上即可。
首先我們需要為 Servlet 配置 multipart-config,哪個 Servlet 負責處理上傳文件,就為哪個 Servlet 配置 multipart-config。在 SpringMVC 中,我們的請求都是通過 DispatcherServlet 進行分發的,所以我們就為 DispatcherServlet 配置 multipart-config。
配置方式如下:
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</serv
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-servlet.xml</param-value>
</init-param>
<multipart-config>
<location>/tmp</location>
<max-file-size>1024</max-file-size>
<max-request-size>10240</max-request-size>
</multipart-config>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
然后在 SpringMVC 的配置文件中提供一個 StandardServletMultipartResolver 實例,注意該實例的 id 必須為 multipartResolver
<bean class="org.springframework.web.multipart.support.StandardServletMultipartResolver" id="multipartResolver">
</bean>
配置完成后,我們就可以開發一個文件上傳接口了,如下:
@RestController
public class FileUploadController {
SimpleDateFormat sdf = new SimpleDateFormat("/yyyy/MM/dd/");
@PostMapping("/upload")
public String fileUpload(MultipartFile file, HttpServletRequest req) {
String format = sdf.format(new Date());
String realPath = req.getServletContext().getRealPath("/img") + format;
File folder = new File(realPath);
if (!folder.exists()) {
folder.mkdirs();
}
String oldName = file.getOriginalFilename();
String newName = UUID.randomUUID().toString() + oldName.substring(oldName.lastIndexOf("."));
try {
file.transferTo(new File(folder, newName));
return req.getScheme() + "://" + req.getRemoteHost() + ":" + req.getServerPort() + "/img" + format + newName;
} catch (IOException e) {
e.printStackTrace();
}
return "error";
}
@PostMapping("/upload2")
public String fileUpload2(HttpServletRequest req) throws IOException, ServletException {
StandardServletMultipartResolver resolver = new StandardServletMultipartResolver();
MultipartFile file = resolver.resolveMultipart(req).getFile("file");
String format = sdf.format(new Date());
String realPath = req.getServletContext().getRealPath("/img") + format;
File folder = new File(realPath);
if (!folder.exists()) {
folder.mkdirs();
}
String oldName = file.getOriginalFilename();
String newName = UUID.randomUUID().toString() + oldName.substring(oldName.lastIndexOf("."));
try {
file.transferTo(new File(folder, newName));
return req.getScheme() + "://" + req.getRemoteHost() + ":" + req.getServerPort() + "/img" + format + newName;
} catch (IOException e) {
e.printStackTrace();
}
return "error";
}
@PostMapping("/upload3")
public String fileUpload3(HttpServletRequest req) throws IOException, ServletException {
String other_param = req.getParameter("other_param");
System.out.println("other_param = " + other_param);
String format = sdf.format(new Date());
String realPath = req.getServletContext().getRealPath("/img") + format;
File folder = new File(realPath);
if (!folder.exists()) {
folder.mkdirs();
}
Part filePart = req.getPart("file");
String oldName = filePart.getSubmittedFileName();
String newName = UUID.randomUUID().toString() + oldName.substring(oldName.lastIndexOf("."));
try {
filePart.write(realPath + newName);
return req.getScheme() + "://" + req.getRemoteHost() + ":" + req.getServerPort() + "/img" + format + newName;
} catch (IOException e) {
e.printStackTrace();
}
return "error";
}
}
我這里一共提供了三個文件上傳接口,其實最終都是通過 StandardServletMultipartResolver 進行處理的。
大致上一看,感覺辦法還挺多,其實仔細看,萬變不離其宗,一會我們看完源碼,相信小伙伴們還能變化出更多寫法。
CommonsMultipartResolver
CommonsMultipartResolver 估計很多人都比較熟悉,這個兼容性很好,就是有點過時了。使用 CommonsMultipartResolver 需要我們首先引入 commons-fileupload 依賴:
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
然后在 SpringMVC 的配置文件中提供 CommonsMultipartResolver 實例,如下:
<bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver" id="multipartResolver">-->
</bean>
接下來開發文件上傳接口就行了:
@PostMapping("/upload")
public String fileUpload(MultipartFile file, HttpServletRequest req) {
String format = sdf.format(new Date());
String realPath = req.getServletContext().getRealPath("/img") + format;
File folder = new File(realPath);
if (!folder.exists()) {
folder.mkdirs();
}
String oldName = file.getOriginalFilename();
String newName = UUID.randomUUID().toString() + oldName.substring(oldName.lastIndexOf("."));
try {
file.transferTo(new File(folder, newName));
return req.getScheme() + "://" + req.getRemoteHost() + ":" + req.getServerPort() + "/img" + format + newName;
} catch (IOException e) {
e.printStackTrace();
}
return "error";
}
這個就沒啥好說,比較容易。
用法掌握了,接下來我們來看原理。
不廢話,直接來看看源碼:
public class StandardServletMultipartResolver implements MultipartResolver {
private boolean resolveLazily = false;
public void setResolveLazily(boolean resolveLazily) {
this.resolveLazily = resolveLazily;
}
@Override
public boolean isMultipart(HttpServletRequest request) {
return StringUtils.startsWithIgnoreCase(request.getContentType(), "multipart/");
}
@Override
public MultipartHttpServletRequest resolveMultipart(HttpServletRequest request) throws MultipartException {
return new StandardMultipartHttpServletRequest(request, this.resolveLazily);
}
@Override
public void cleanupMultipart(MultipartHttpServletRequest request) {
if (!(request instanceof AbstractMultipartHttpServletRequest) ||
((AbstractMultipartHttpServletRequest) request).isResolved()) {
try {
for (Part part : request.getParts()) {
if (request.getFile(part.getName()) != null) {
part.delete();
}
}
}
catch (Throwable ex) {
}
}
}
}
這里滿打滿算就四個方法,其中一個還是 set 方法,我們來看另外三個功能性方法:
在這個過程中涉及到 StandardMultipartHttpServletRequest 對象,我們也來稍微說一下:
public StandardMultipartHttpServletRequest(HttpServletRequest request, boolean lazyParsing)
throws MultipartException {
super(request);
if (!lazyParsing) {
parseRequest(request);
}
}
private void parseRequest(HttpServletRequest request) {
try {
Collection<Part> parts = request.getParts();
this.multipartParameterNames = new LinkedHashSet<>(parts.size());
MultiValueMap<String, MultipartFile> files = new LinkedMultiValueMap<>(parts.size());
for (Part part : parts) {
String headerValue = part.getHeader(HttpHeaders.CONTENT_DISPOSITION);
ContentDisposition disposition = ContentDisposition.parse(headerValue);
String filename = disposition.getFilename();
if (filename != null) {
if (filename.startsWith("=?") && filename.endsWith("?=")) {
filename = MimeDelegate.decode(filename);
}
files.add(part.getName(), new StandardMultipartFile(part, filename));
}
else {
this.multipartParameterNames.add(part.getName());
}
}
setMultipartFiles(files);
}
catch (Throwable ex) {
handleParseFailure(ex);
}
}
StandardMultipartHttpServletRequest 對象在構建的過程中,會自動進行請求解析,調用 getParts 方法獲取所有的項,然后進行判斷,將文件和普通參數分別保存下來備用。
這塊的邏輯比較簡單。
再來看 CommonsMultipartResolver。
先來看它的 isMultipart 方法:
@Override
public boolean isMultipart(HttpServletRequest request) {
return ServletFileUpload.isMultipartContent(request);
}
public static final boolean isMultipartContent(
HttpServletRequest request) {
if (!POST_METHOD.equalsIgnoreCase(request.getMethod())) {
return false;
}
return FileUploadBase.isMultipartContent(new ServletRequestContext(request));
}
ServletFileUpload.isMultipartContent 方法其實就在我們引入的 commons-fileupload 包中。它的判斷邏輯分兩步:首先檢查是不是 POST 請求,然后檢查 content-type 是不是以 multipart/ 開始。
再來看它的 resolveMultipart 方法:
@Override
public MultipartHttpServletRequest resolveMultipart(final HttpServletRequest request) throws MultipartException {
if (this.resolveLazily) {
return new DefaultMultipartHttpServletRequest(request) {
@Override
protected void initializeMultipart() {
MultipartParsingResult parsingResult = parseRequest(request);
setMultipartFiles(parsingResult.getMultipartFiles());
setMultipartParameters(parsingResult.getMultipartParameters());
setMultipartParameterContentTypes(parsingResult.getMultipartParameterContentTypes());
}
};
}
else {
MultipartParsingResult parsingResult = parseRequest(request);
return new DefaultMultipartHttpServletRequest(request, parsingResult.getMultipartFiles(),
parsingResult.getMultipartParameters(), parsingResult.getMultipartParameterContentTypes());
}
}
根據 resolveLazily 屬性值,選擇兩種不同的策略將當前對象重新構建成一個 DefaultMultipartHttpServletRequest 對象。如果 resolveLazily 為 true,則在 initializeMultipart 方法中進行請求解析,否則先解析,再構建 DefaultMultipartHttpServletRequest 對象。
具體的解析方法如下:
protected MultipartParsingResult parseRequest(HttpServletRequest request) throws MultipartException {
String encoding = determineEncoding(request);
FileUpload fileUpload = prepareFileUpload(encoding);
try {
List<FileItem> fileItems = ((ServletFileUpload) fileUpload).parseRequest(request);
return parseFileItems(fileItems, encoding);
}
catch (FileUploadBase.SizeLimitExceededException ex) {
//...
}
}
protected MultipartParsingResult parseFileItems(List<FileItem> fileItems, String encoding) {
MultiValueMap<String, MultipartFile> multipartFiles = new LinkedMultiValueMap<>();
Map<String, String[]> multipartParameters = new HashMap<>();
Map<String, String> multipartParameterContentTypes = new HashMap<>();
for (FileItem fileItem : fileItems) {
if (fileItem.isFormField()) {
String value;
String partEncoding = determineEncoding(fileItem.getContentType(), encoding);
try {
value = fileItem.getString(partEncoding);
}
catch (UnsupportedEncodingException ex) {
value = fileItem.getString();
}
String[] curParam = multipartParameters.get(fileItem.getFieldName());
if (curParam == null) {
multipartParameters.put(fileItem.getFieldName(), new String[] {value});
}
else {
String[] newParam = StringUtils.addStringToArray(curParam, value);
multipartParameters.put(fileItem.getFieldName(), newParam);
}
multipartParameterContentTypes.put(fileItem.getFieldName(), fileItem.getContentType());
}
else {
CommonsMultipartFile file = createMultipartFile(fileItem);
multipartFiles.add(file.getName(), file);
}
}
return new MultipartParsingResult(multipartFiles, multipartParameters, multipartParameterContentTypes);
}
這里的解析就是首先獲取到 FileItem 集合,然后調用 parseFileItems 方法進行進一步的解析。在進一步的解析中,會首先判斷這是文件還是普通參數,如果是普通參數,則保存到 multipartParameters 中,具體保存過程中還會判斷是否為數組,然后再將參數的 ContentType 保存到 multipartParameterContentTypes 中,文件則保存到 multipartFiles 中,最后由三個 Map 構成一個 MultipartParsingResult 對象并返回。
至此,StandardServletMultipartResolver 和 CommonsMultipartResolver 源碼就和大家說完了,可以看到,還是比較容易的。
最后,我們再來梳理一下解析流程。
以如下接口為例(因為在實際開發中一般都是通過如下方式上傳文件):
@PostMapping("/upload")
public String fileUpload(MultipartFile file, HttpServletRequest req) {
String format = sdf.format(new Date());
String realPath = req.getServletContext().getRealPath("/img") + format;
File folder = new File(realPath);
if (!folder.exists()) {
folder.mkdirs();
}
String oldName = file.getOriginalFilename();
String newName = UUID.randomUUID().toString() + oldName.substring(oldName.lastIndexOf("."));
try {
file.transferTo(new File(folder, newName));
return req.getScheme() + "://" + req.getRemoteHost() + ":" + req.getServerPort() + "/img" + format + newName;
} catch (IOException e) {
e.printStackTrace();
}
return "error";
}
這里 MultipartFile 對象主要就是在參數解析器中獲取的,這里涉及到的參數解析器是 RequestParamMethodArgumentResolver。
在 RequestParamMethodArgumentResolver#resolveName 方法中有如下一行代碼:
if (servletRequest != null) {
Object mpArg = MultipartResolutionDelegate.resolveMultipartArgument(name, parameter, servletRequest);
if (mpArg != MultipartResolutionDelegate.UNRESOLVABLE) {
return mpArg;
}
}
這個方法會進行請求解析,返回 MultipartFile 對象或者 MultipartFile 數組。
@Nullable
public static Object resolveMultipartArgument(String name, MethodParameter parameter, HttpServletRequest request)
throws Exception {
MultipartHttpServletRequest multipartRequest =
WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class);
boolean isMultipart = (multipartRequest != null || isMultipartContent(request));
if (MultipartFile.class == parameter.getNestedParameterType()) {
if (!isMultipart) {
return null;
}
if (multipartRequest == null) {
multipartRequest = new StandardMultipartHttpServletRequest(request);
}
return multipartRequest.getFile(name);
}
else if (isMultipartFileCollection(parameter)) {
if (!isMultipart) {
return null;
}
if (multipartRequest == null) {
multipartRequest = new StandardMultipartHttpServletRequest(request);
}
List<MultipartFile> files = multipartRequest.getFiles(name);
return (!files.isEmpty() ? files : null);
}
else if (isMultipartFileArray(parameter)) {
if (!isMultipart) {
return null;
}
if (multipartRequest == null) {
multipartRequest = new StandardMultipartHttpServletRequest(request);
}
List<MultipartFile> files = multipartRequest.getFiles(name);
return (!files.isEmpty() ? files.toArray(new MultipartFile[0]) : null);
}
else if (Part.class == parameter.getNestedParameterType()) {
if (!isMultipart) {
return null;
}
return request.getPart(name);
}
else if (isPartCollection(parameter)) {
if (!isMultipart) {
return null;
}
List<Part> parts = resolvePartList(request, name);
return (!parts.isEmpty() ? parts : null);
}
else if (isPartArray(parameter)) {
if (!isMultipart) {
return null;
}
List<Part> parts = resolvePartList(request, name);
return (!parts.isEmpty() ? parts.toArray(new Part[0]) : null);
}
else {
return UNRESOLVABLE;
}
}
首先獲取 multipartRequest 對象,然后再從中獲取文件或者文件數組。如果我們使用 StandardServletMultipartResolver 做文件上傳,這里獲取到的 multipartRequest 就是 StandardMultipartHttpServletRequest;如果我們使用 CommonsMultipartResolver 做文件上傳,這里獲取到的 multipartRequest 就是 DefaultMultipartHttpServletRequest。
2021最新完整面試題及答案(都整理成文檔),有很多干貨,包含mysql,netty,spring,線程,spring cloud、JVM、源碼、算法等詳細講解,詳細的學習規劃圖等學習資料,私信我:Java 獲取
最開始是為了解決圖片保存到MySQL數據庫的問題,之前沒做過,后來自己查資料。找到兩種有效的方式。
第一種是直接把圖片轉化成字節流存進數據庫,這樣的例子很多,好處很明顯,存進去以后,可以直接備份數據庫帶走,簡單方面,壞處就是圖片占用內存,一旦數量上來,那么對內存庫的壓力很大,在高并發訪問的情況下,占用資源較大,所以一般情況下,很多公司都不是采用這樣的方式。而是采用第二種,把圖片上傳到服務器的文件夾內,然后數據庫直接存儲圖片的地址,這樣的壞處就是項目的遷移,文件夾也要跟著備份,備份兩次,好處就很明顯了,顯然存地址跟存內容占用的空間大小就很明顯,大大減輕了數據庫的壓力。因此本文采用的就是數據庫存儲圖片地址,圖片直接存儲在本機文件夾中。
營業執照選擇自營,必須填寫營業執照代碼跟照片,非自營的,可以不用填寫。代碼如下:
<tr>
<td style="text-align: right;"><font size="2px">營業執照代碼</font></td>
<td> <input type="radio" name="ra" id="ra" checked="true" onclick="_change(this);" value="a"/> 自營
<input type="radio" name="ra" id="ra" onclick="_change(this); "value="b"/> 非自營
<td><font color="#999999">* 自營必填,同時上傳營業執照照片</font></td>
</td> <div id="prvid"></div>
</tr>
上傳照片在form表單里必須填寫 enctype="multipart/form-data",否則圖片就無法上傳,只能上傳文字信息,但是加了這條語句以后,后臺就無法用request.getParameter(arg0)來獲取參數了,因為上傳的信息全部轉化成了字節流,這是我添加以后一直出錯發現的問題所在。
接下來我們需要編寫一個upload的類來處理圖片的上傳,這個類是網上找的,需要添加包
cos.jar,下載地址稍后會在留言里。代碼如下
import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import com.oreilly.servlet.multipart.FilePart;
import com.oreilly.servlet.multipart.MultipartParser;
import com.oreilly.servlet.multipart.ParamPart;
import com.oreilly.servlet.multipart.Part;
public class Upload {
public static Map<String, String> upload(HttpServletRequest request,
int maxSize, String path) {
//以map形式保存數據 key對應保存的是獲取界面上的name名稱 value保存的是獲取界面上的name對應的值
Map<String, String> map = new HashMap<String, String>();
Part part = null;
try {
MultipartParser mrequest = new MultipartParser(request, maxSize);
mrequest.setEncoding("utf-8");
//遍歷所有的part組
while ((part = mrequest.readNextPart()) != null) {
if (part.isFile()) { //判斷是否是文件
FilePart filepart = (FilePart) part;//轉化成文件組
String fileName = filepart.getFileName();//得到文件名
if (fileName != null && fileName.length() > 0) {
// 取得擴展名
String fileExtName = fileName.substring(
fileName.lastIndexOf(".") + 1).toLowerCase();
// 只上傳圖片 //判斷圖片上傳的格式是否符合 后綴名是否有效
if (fileExtName.equalsIgnoreCase("jpeg")
|| fileExtName.equalsIgnoreCase("png")||
fileExtName.equalsIgnoreCase("jpg")
|| fileExtName.equalsIgnoreCase("gif")
|| fileExtName.equalsIgnoreCase("ico")
|| fileExtName.equalsIgnoreCase("bmp")
|| fileExtName.equalsIgnoreCase("flv")
|| fileExtName.equalsIgnoreCase("mp4")
|| fileExtName.equalsIgnoreCase("mp3")) {
/*String newFileName = new Date().getTime() + "."+ fileExtName;//重新改文件名 文件名+擴展名 */
String newFileName =new Date().getTime() +fileName;//不改圖片名字
String newPath = path + "/" + newFileName; //文件處理文件上傳的路徑
File newFile = new File(newPath);
filepart.writeTo(newFile); //將文件真正寫入到對應的文件夾中
//filepart.getName() 得到 request 要接收的參數的名字
map.put("newFileName", newFileName);
map.put(filepart.getName(), newFileName);//把文件信息保存到map中
map.put("newFile", newFile.toString());
} else {
map.put("geshi", "geshi");
continue;
}// 說明上傳的不是圖片
} else {
map.put("yes","yes");
continue; // 說明沒有選擇上傳圖片
}
} else if (part.isParam()) { //判斷是否是參數
ParamPart paramPart = (ParamPart) part;
map.put(paramPart.getName(), paramPart.getStringValue());
}
}
} catch (IOException e) {
e.printStackTrace();
}
return map;
}
}
else if (part.isParam()) { //判斷是否是參數
ParamPart paramPart = (ParamPart) part;
map.put(paramPart.getName(), paramPart.getStringValue());
}
通過觀察代碼,熟悉思路,大概就是先看這個part是否是文件,如果是文件,則進行一系列文件處理,如果不是文件,看是否是參數,如果是參數,則依次用map存儲起來,因此在后臺就可以map.get()來獲取參數了,實驗以后發現確實可行,因此后臺代碼如下:
后臺servlet代碼:
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
request.setCharacterEncoding("UTF-8");
String PATH = "image/license_pic";
String path = "E:/"+PATH;
Map<String, String> map = Upload.upload(request, 1024 * 1024 * 10, path);
// String newfile = map.get("newFile");
String newFileName =PATH+ map.get("newFileName");
User user = new User();
Shop shop = new Shop();
user.setUsername(map.get("username"));
user.setPassword(map.get("password"));
shop.setName(map.get("name"));
shop.setAddress(map.get("address"));
shop.setYear(map.get("year"));
shop.setPhone(map.get("phone"));
shop.setMaster(map.get("master"));
shop.setIdentity(map.get("identity"));
shop.setLicense(map.get("license"));
shop.setTelephone(map.get("telephone"));
shop.setNote(map.get("note"));
shop.setLicense_pic(newFileName);
System.out.println(newFileName);
UserServiceImpl us = new UserServiceImpl();
ShopServiceImpl ss = new ShopServiceImpl();
try {
int i = 0, j = 0;
i = us.insertUser(user);
System.out.println(user.getUsername());
int id = us.selectByName(user.getUsername()).getId();
j = ss.insertShop(shop, id);
if (i == 1 && j == 1) {
System.out.println("插入成功!");
request.getSession().setAttribute("u", user);
request.getRequestDispatcher("/admin/login/login.jsp").forward(request, response);
} else {
System.out.println("插入失敗!");
response.sendRedirect("/shop_Register3/admin/login/register.jsp?error=yes");
}
} catch (Exception e) {
e.printStackTrace();
}
}
請點擊此處輸入圖片描最后得到結果輸出,輸出顯示文件名稱,然后用戶名,最后插入成功,說明是可行的,查看自己的E盤,確實看到照片已經上傳成功了,這是一個大概的步驟,具體代碼因為項目代碼多,就不全部上傳了,有問題可以留言。
項目目錄結構大致如下:
正如我在上圖紅線畫的三個東西:Dao、service、servlet 這三層是主要的結構,類似 MVC 架構,Dao是模型實體類(邏輯層),service是服務層,servlet是視圖層,三者協作共同完成項目。
這里的User是由user表來定義的一個類,再封裝增刪改查等操作,實現從數據庫查詢與插入,修改與刪除等操作,并實現了分頁操作,也實現了將圖片放到服務器上運行的效果。
Dao層:主要實現了User類的定義,接口IUserDao的定義與實現(UserDaoImpl);
service層:直接定義一個接口類IUserService,與IUserDao相似,再實現其接口類UserServiceImpl,直接實例化UserDaoImpl再調用其方法來實現自己的方法,重用了代碼。詳見代碼吧;
servlet層:起初是將表User 的每個操作方法都定義成一個servlet 去實現,雖然簡單,但是太多了,不好管理,于是利用 基類BaseServlet 實現了“反射機制”,通過獲取的 action 參數自己智能地調用對應的方法,而UserServlet則具體實現自己的方法,以供調用,方便許多,詳見之前的博文或下述代碼。
將文件上傳到 tomcat 服務器的編譯后運行的過程的某個文件關鍵要在每次編譯后手動為其創建該文件夾來存放相應的上傳文件,否則會導致每次重啟 tomcat 服務器后該編譯后的工程覆蓋了原先的,導致上傳文件存放的文件夾不存在,導致代碼找不到該文件夾而報錯,即上傳不成功。如下圖所示:
主要是考慮圖片路徑的問題,手工設置路徑肯定不能保證不重復,所以取到上傳圖片的后綴名后利用隨機生成的隨機數作為圖片名,這樣就不會重復名字了:
String extendedName = picturePath.substring(picturePath.lastIndexOf("."),// 截取從最后一個'.'到字符串結束的子串。
picturePath.length());
// 把文件名稱重命名為全球唯一的文件名
String uniqueName = UUID.randomUUID().toString();
saveFileName = uniqueName + extendedName;// 拼接路徑名
增加用戶時代碼如下:
// 增
public void add(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("add方法被調用");
// 獲取數據
int id = 0;
String username = null;
String password = null;
String sex = null;
Date birthday = null;
String address = null;
String saveFileName = null;
String picturePath = null;
// 得到表單是否以enctype="multipart/form-data"方式提交
boolean isMulti = ServletFileUpload.isMultipartContent(request);
if (isMulti) {
// 通過FileItemFactory得到文件上傳的對象
FileItemFactory fif = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(fif);
try {
List<FileItem> items = upload.parseRequest(request);
for (FileItem item : items) {
// 判斷是否是普通表單控件,或者是文件上傳表單控件
boolean isForm = item.isFormField();
if (isForm) {// 是普通表單控件
String name = item.getFieldName();
if ("id".equals(name)) {
id = Integer.parseInt(item.getString("utf-8"));
System.out.println(id);
}
if ("sex".equals(name)) {
sex = item.getString("utf-8");
System.out.println(sex);
}
if ("username".equals(name)) {
username = item.getString("utf-8");
System.out.println(username);
}
if ("password".equals(name)) {
password = item.getString("utf-8");
System.out.println(password);
}
if ("birthday".equals(name)) {
String birthdayStr = item.getString("utf-8");
SimpleDateFormat sdf = new SimpleDateFormat(
"yyyy-MM-dd");
try {
birthday = sdf.parse(birthdayStr);
} catch (ParseException e) {
e.printStackTrace();
}
System.out.println(birthday);
}
if ("address".equals(name)) {
address = item.getString("utf-8");
System.out.println(address);
}
if ("picturePath".equals(name)) {
picturePath = item.getString("utf-8");
System.out.println(picturePath);
}
} else {// 是文件上傳表單控件
// 得到文件名 xxx.jpg
String sourceFileName = item.getName();
// 得到文件名的擴展名:.jpg
String extendedName = sourceFileName.substring(
sourceFileName.lastIndexOf("."),
sourceFileName.length());
// 把文件名稱重命名為全球唯一的文件名
String uniqueName = UUID.randomUUID().toString();
saveFileName = uniqueName + extendedName;
// 得到上傳到服務器上的文件路徑
// C:\apache-tomcat-7.0.47\webapps\taobaoServlet4\upload\xx.jpg
String uploadFilePath = request.getSession()
.getServletContext().getRealPath("upload/");
File saveFile = new File(uploadFilePath, saveFileName);
// 把保存的文件寫出到服務器硬盤上
try {
item.write(saveFile);
} catch (Exception e) {
e.printStackTrace();
}
}
}
} catch (NumberFormatException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (FileUploadException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// 2、封裝數據
User user = new User(id, username, password, sex, birthday, address,
saveFileName);
// 3、調用邏輯層API
IUserService iUserService = new UserServiceImpl();
// 4、控制跳轉
HttpSession session = request.getSession();
if (iUserService.save(user) > 0) {
System.out.println("添加新用戶成功!");
List<User> users = new ArrayList<User>();
users = iUserService.listAll();
session.setAttribute("users", users);
response.sendRedirect("UserServlet?action=getPage");
} else {
System.out.println("添加新用戶失敗!");
PrintWriter out = response.getWriter();
out.print("<script type='text/javascript'>");
out.print("alert('添加新用戶失敗!請重試!');");
out.print("</script>");
}
}
修改用戶時注意考慮圖片更改和沒更改這兩種情況,圖片更改時要先獲取原圖片并刪除其在服務器上的圖片,再添加新圖片到服務器;圖片不更改時則無需更新圖片路徑。
// 改
public void update(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("update方法被調用");
HttpSession session = request.getSession();
// 獲取數據
int id = (int)session.getAttribute("id");
String username = null;
String password = null;
String sex = null;
Date birthday = null;
String address = null;
String saveFileName = null;
String picturePath = null;
IUserService iUserService = new UserServiceImpl();
// 得到表單是否以enctype="multipart/form-data"方式提交
boolean isMulti = ServletFileUpload.isMultipartContent(request);
if (isMulti) {
// 通過FileItemFactory得到文件上傳的對象
FileItemFactory fif = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(fif);
try {
List<FileItem> items = upload.parseRequest(request);
for (FileItem item : items) {
// 判斷是否是普通表單控件,或者是文件上傳表單控件
boolean isForm = item.isFormField();
if (isForm) {// 是普通表單控件
String name = item.getFieldName();
if ("sex".equals(name)) {
sex = item.getString("utf-8");
System.out.println(sex);
}
if ("username".equals(name)) {
username = item.getString("utf-8");
System.out.println(username);
}
if ("password".equals(name)) {
password = item.getString("utf-8");
System.out.println(password);
}
if ("birthday".equals(name)) {
String birthdayStr = item.getString("utf-8");
SimpleDateFormat sdf = new SimpleDateFormat(
"yyyy-MM-dd");
try {
birthday = sdf.parse(birthdayStr);
} catch (ParseException e) {
e.printStackTrace();
}
System.out.println(birthday);
}
if ("address".equals(name)) {
address = item.getString("utf-8");
System.out.println(address);
}
if ("picturePath".equals(name)) {
picturePath = item.getString("utf-8");
System.out.println(picturePath);
}
} else {// 是文件上傳表單控件
// 得到文件名 xxx.jpg
picturePath = item.getName();
if (picturePath != "") {// 有選擇要上傳的圖片
// 得到文件名的擴展名:.jpg
String extendedName = picturePath.substring(
picturePath.lastIndexOf("."),// 截取從最后一個'.'到字符串結束的子串。
picturePath.length());
// 把文件名稱重命名為全球唯一的文件名
String uniqueName = UUID.randomUUID().toString();
saveFileName = uniqueName + extendedName;// 拼接路徑名
// 得到上傳到服務器上的文件路徑
// C:\apache-tomcat-7.0.47\webapps\CommonhelloWorldServlet\upload\xx.jpg
String uploadFilePath = request.getSession()
.getServletContext().getRealPath("upload/");
File saveFile = new File(uploadFilePath,
saveFileName);
// 把保存的文件寫出到服務器硬盤上
try {
item.write(saveFile);
} catch (Exception e) {
e.printStackTrace();
}
// 3、調用邏輯層 API
// 根據id查詢用戶并獲取其之前的圖片
User user = iUserService.getUserById(id);
String oldPic = user.getPicturePath();
String oldPicPath = uploadFilePath + "\" + oldPic;
File oldPicTodelete = new File(oldPicPath);
oldPicTodelete.delete();// 刪除舊圖片
}
}
}
} catch (NumberFormatException e) {
e.printStackTrace();
} catch (FileUploadException e) {
e.printStackTrace();
}
}
System.out.println(id + "\t" + username + "\t" + password + "\t" + sex
+ "\t" + address + "\t" + picturePath + "\t" + birthday);
// 2、封裝數據
User user = new User(id, username, password, sex, birthday, address,
saveFileName);
if (iUserService.update(user) > 0) {
System.out.println("修改數據成功!");
List<User> users = new ArrayList<User>();
users = iUserService.listAll();
session.setAttribute("users", users);
// 4、控制跳轉
response.sendRedirect("UserServlet?action=getPage");
} else {
System.out.println("修改數據失敗!");
PrintWriter out = response.getWriter();
out.print("<script type='text/javascript'>");
out.print("alert('修改數據失敗!請重試!');");
out.print("</script>");
}
}
刪除的話就比較簡單了,直接獲取原圖片路徑并刪除,則原圖片在服務器上被刪除。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。