目录
然后,在Model的Dao中编写根据id查询Painting对象的方法
然后,在Model的Service中编写根据id查询Painting对象的方法:调用Dao中的工具方法,然后加一点其他的辅助逻辑代码
然后,在Controller编写,接受前台【修改】请求的方法:接受前台请求,根据id查painting,然后跳转到update.jsp【作品更新】界面
然后,在update.jsp中获取数据,即数据回填(注意:下拉框的回填是比较难得部分)
首先在,工具类XmlDataSource中编写,更新数据的方法(方便Dao调用啦)
然后,在前台的update.jsp准备好了之后,设置form表单提交地址,并在后台接受这个提交请求
然后,View准备好了,Model准备好了,编写Controller部分
1.修改需求说明:
2.更新功能具体编写
(1)引入update.jsp这个“作品更新”的前端文件
“作品更新”update.jsp页面和“新增作品”create.jsp页面,代码内容大部分相同,只有几点不同:
……………………………………………………
(2)开始编写:数据获取 和 回填部分
首先,设置【修改】超链接的跳转地址
注意其附带了俩参数method和id;
……………………………………………………
然后,在Model的Dao中编写根据id查询Painting对象的方法
……………………………………………………
然后,在Model的Service中编写根据id查询Painting对象的方法:调用Dao中的工具方法,然后加一点其他的辅助逻辑代码
……………………………………………………
然后,在Controller编写,接受前台【修改】请求的方法:接受前台请求,根据id查painting,然后跳转到update.jsp【作品更新】界面
……………………………………………………
然后,在update.jsp中获取数据,即数据回填(注意:下拉框的回填是比较难得部分)
update.jsp内容:
<%@page contentType="text/html;charset=utf-8"%>
<!-- 修改油画页面 -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>作品更新</title>
<link rel="stylesheet" type="text/css" href="css\create.css">
<script type="text/javascript" src="js/jquery-3.4.1.min.js"></script>
<script type="text/javascript" src="js/validation.js"></script>
<script type="text/javascript">
<!-- 提交前表单校验 -->
function checkSubmit(){
var result = true;
var r1 = checkEmpty("#pname","#errPname");
var r2 = checkCategory('#category', '#errCategory');
var r3 = checkPrice('#price', '#errPrice');
var r4 = checkFile('#painting', '#errPainting');
var r5 = checkEmpty('#description', '#errDescription');
if (r1 && r2 && r3 && r4 && r5){
return true;
}else{
return false;
}
}
<!--jQUery页面就绪函数,作用是整个html被解析后,来执行这个函数的代码,相当于是一个页面初始化函数;;以前在学习jQuery的时候接触过-->
$(function(){
// $("#category"):是jQuery选择器;执行时机:在html被解释完了之后,才会被执行;然后,jQUery是JavaScript这个浏览器脚本语言的小框架,所以这个肯定是在浏览器上执行的;
// ${painting.category}:是el表达式;执行时机:JSP渲染的时候,在服务器端生成的;
// jQuery的val()方法:可以根据传入的值,根据传入的值,自动把与之匹配的选项进行选中;
$("#category").val(${painting.category});
})
</script>
</head>
<body>
<div class="container">
<fieldset>
<legend>作品更新</legend>
<form action="[这里写更新URL]" method="post"
autocomplete="off" enctype="multipart/form-data"
onsubmit = "return checkSubmit()">
<ul class="ulform">
<li>
<span>油画名称</span>
<span id="errPname"></span>
<input id="pname" name="pname" onblur="checkEmpty('#pname','#errPname')" value="${painting.pname}"/>
</li>
<li>
<span>油画类型</span>
<span id="errCategory"></span>
<select id="category" name="category" onchange="checkCategory('#category','#errCategory')">
<option value="-1">请选择油画类型</option>
<option value="1">现实主义</option>
<option value="2">抽象主义</option>
</select>
</li>
<li>
<span>油画价格</span>
<span id="errPrice"></span>
<input id="price" name="price" onblur="checkPrice('#price','#errPrice')" value="${painting.price}"/>
</li>
<li>
<span>作品预览</span><span id="errPainting"></span><br/>
<img id="preview" src="${painting.preview}" style="width:361px;height:240px"/><br/>
<input id="painting" name="painting" type="file" style="padding-left:0px;" accept="image/*"/>
</li>
<li>
<span>详细描述</span>
<span id="errDescription"></span>
<textarea
id="description" name="description"
onblur="checkEmpty('#description','#errDescription')"
>${painting.description }</textarea>
</li>
<li style="text-align: center;">
<button type="submit" class="btn-button">提交表单</button>
</li>
</ul>
</form>
</fieldset>
</div>
</body>
</html>
update.jsp几点说明:
● 油画名称、油画价格、详细描述这三个很简单:直接利用el表达式获取设置就行了
● 油画类型,需要通过页面就绪函数来辅助完成(这个是比较难的地方)
● 油画的作品预览,设置<img>的src属性
……………………………………………………
(3)开始编写:数据提交 和 更新xml部分
首先在,工具类XmlDataSource中编写,更新数据的方法(方便Dao调用啦)
XmlDataSource类:这儿着重看update()更新方法
package com.imooc.mgallery.utils;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.List;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import com.imooc.mgallery.entity.Painting;
/**
* 数据源类,将xml文件解析为Java对象
*
* @author dell
*
*/
public class XmlDataSource {
// 为了保证在同一时间,内存中只有一份xml的Document对象,即为了保证加载的xml对象全局唯一
// 通过static静态关键字保证数据的全局唯一性;(自然也可以通过单例模式)
private static List<Painting> data = new ArrayList<Painting>(); // 在XmlDataSource类加载的时候,就会创建data对象,这个对象隶属于XmlDataSource类,可以保证是全局唯一;
private static String dataFile; // xml文件的地址;
static {
// 程序运行编译后,src目录下得java文件会被编译为class文件,这些class文件会被放在classes目录下,而同样处于src目录下的painting.xml文件也会放在classes目录下;
// XmlDataSource.class.getResoure()得到classes目录的根路径,然后在classes目录的根路径下找到painting.xml,然后getPath()获得painting.xml文件的完整的物理磁盘的地址;
dataFile = XmlDataSource.class.getResource("/painting.xml").getPath();
//System.out.println(dataFile);
// 如painting.xml文件的地址是:c:\new style\painting.xml;可以发现,new和style之间有一个空格,这个空格是个特殊字符;
// datFile得到painting.xml文件地址的时候,会进行base64转换,实际dataFile的值会是:c:\new%20style\painting.xml,即空格被转化成了%20;
// 但是如果在后续中,利用JavaIO对painting.xml文件按照“c:\new%20style\painting.xml”读取时,会提示路径找不到,因为%20不会被JavaIO解析;需要手动的将%20转换为空格;
// URLDecoder的作用就是:将base64转回普通的字符串;
reload();
}
/**
* 读取xml文件内容到内存中,把这个功能,提炼成了一个方法
*/
private static void reload() {
data.clear();// 先清空
URLDecoder decoder = new URLDecoder();
try {
dataFile = decoder.decode(dataFile, "UTF-8"); // 这个需要捕获“不支持的编码格式”异常
//System.out.println(dataFile);
SAXReader reader = new SAXReader();
Document document = reader.read(dataFile); // 需要捕获“DocumentException”异常
List<Node> nodes = document.selectNodes("/root/painting");
for(Node node:nodes) {
Element element = (Element)node;
// 提取数据,如何将数据转换成Java对象?通过什么载体来保存油画的数据?所以,需要开发对应的JavaBean承载油画数据;
String id = element.attributeValue("id");
String pname = element.elementText("pname");
//
Painting painting = new Painting();
painting.setId(Integer.parseInt(id));
painting.setPname(pname);
// 剩余几个采用紧凑的写法
painting.setCategory(Integer.parseInt(element.elementText("category")));
painting.setPrice(Integer.parseInt(element.elementText("price")));
painting.setPreview(element.elementText("preview"));
painting.setDescription(element.elementText("description"));
// 将对象存储到data集合中;
data.add(painting); // 这样以后,当XmlDataSource这个类被加载以后,data集合中就保存了完整的油画信息;
}
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (DocumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 为了保证外部可以访问data集合,需要给data增加一个出口;;;
* 这儿添加一个方法,getRawData():即获取最原始的信息;
* @return
*/
public static List<Painting> getRawData(){
return data;
}
/**
* 向xml中添加
* @param painting :从前端封装好的Painting对象,一个Painting对象就是一个油画数据
* @throws DocumentException
*/
public static void append(Painting painting) {
//1.读取XML文档,得到Document对象
SAXReader reader = new SAXReader();
Writer writer = null;
try {
Document document = reader.read(dataFile); // xml文件地址,上面已经定义好了,直接拿来用就可以了
//2.创建新的painting
Element root = document.getRootElement(); // 获取根节点
Element p = root.addElement("painting"); // 创建一个新的节点
// 下面,就根据原始xml的结构,来以此设置它的属性和子节点了
//3.创建painting节点的各个子节点
p.addAttribute("id", String.valueOf(data.size()+1)); // 直接在原有节点数的基础上加一就可以了;
Element pname = p.addElement("pname");
pname.setText(painting.getPname());
p.addElement("category").setText(painting.getCategory().toString());
p.addElement("price").setText(painting.getPrice().toString());
p.addElement("preview").setText(painting.getPreview());
p.addElement("description").setText(painting.getDescription());
// 自此,就创建了一个新的painting节点,属性节点已经设置好了;;即内存中的Document对象就形成了一个全新的油画数据;
// 接下来,需要把内存中的油画数据,写入到xml文件中
//4.写入XML,完成追加操作
writer = new OutputStreamWriter(new FileOutputStream(dataFile),"UTF-8");
document.write(writer);
//System.out.println(dataFile); // 测试用,测试后删除
} catch (DocumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch(Exception e) {
e.printStackTrace();
}finally {
if(writer != null) { // 这儿将writer的关闭操作,写在了finally中;
try {
writer.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
reload();// 将重新加载的方法,写在了finally中,这或许也是为了保证reaload()方法一定会被执行的 一个保证措施吧
}
}
/**
* 更新操作
* @param painting
*/
public static void update(Painting painting) {
SAXReader reader = new SAXReader();
Writer writer = null;
try {
Document document = reader.read(dataFile);
// 利用XPath表达式去查询对应id的节点
List<Node> nodes = document.selectNodes("/root/painting[@id="+painting.getId()+"]");
// 如果根据传入的id没有搜索到对应点的painting
if(nodes.size() == 0) {
throw new RuntimeException("id="+painting.getId()+"编号油画不存在。");
}
Element p = (Element)nodes.get(0); // 将nodes集合中唯一的Element节点提取出来
// p.selectSingleNode("pname")获取,某一个(大的)Painting节点的,值为“pname”的子节点;;返回值类型当然是一个Element,然后直接调用setTest()重新赋值就可以了;
p.selectSingleNode("pname").setText(painting.getPname());
p.selectSingleNode("category").setText(painting.getCategory().toString());
p.selectSingleNode("price").setText(painting.getPrice().toString());
p.selectSingleNode("preview").setText(painting.getPreview());
p.selectSingleNode("description").setText(painting.getDescription());
// 上面设置以后以后,在内存中就会产生一个包含了新数据的painting节点;
writer = new OutputStreamWriter(new FileOutputStream(dataFile),"UTF-8");
document.write(writer);//利用Document文档对象的write()方法,对xml文件进行回写,将数据更新在xml中;
} catch (DocumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnsupportedEncodingException e) { // 不支持的编码异常
// TODO Auto-generated catch block
e.printStackTrace();
} catch (FileNotFoundException e) { // 文件未发现异常
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
if(writer != null) {
try {
writer.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
reload(); //由于xml文件发生了改变,需要调用reload方法,是的xml文件在内存中的那一份copy保持最新
}
}
}
XmlDataSource类的update()方法的几点说明:
(1)首先根据id查询xml节点,使用了XPath;
(2)注意一下,当搜寻不到的时候的异常处理策略;
(3)注意一下,Element对象的selectSingleNode()方法的用法,这儿是单独获取某一个节点;
(4)writer.close();这个操作放在finally块中;
(5)更新完毕后,记得reload()一下,及时更新xml文件在内存中的那一份copy;
……………………………………………………
然后,在Dao和Service中编写调用方法:
……………………………………………………
然后,结合“隐藏域”,来处理前端的额update.jsp:
update.jsp前端文件:
<%@page contentType="text/html;charset=utf-8"%>
<!-- 修改油画页面 -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>作品更新</title>
<link rel="stylesheet" type="text/css" href="css\create.css">
<script type="text/javascript" src="js/jquery-3.4.1.min.js"></script>
<script type="text/javascript" src="js/validation.js"></script>
<script type="text/javascript">
<!-- 提交前表单校验 -->
function checkSubmit(){
var result = true;
var r1 = checkEmpty("#pname","#errPname");
var r2 = checkCategory('#category', '#errCategory');
var r3 = checkPrice('#price', '#errPrice');
//var r4 = checkFile('#painting', '#errPainting');
var r4 = null;
// 如果这个值=1的话,说明前面新上传了一个图片文件
if($("#isPreviewModified").val() == "1"){
r4 = checkFile('#painting', '#errPainting');
}else{
// 如果没有上传新的文件,r4就=true,这样在客户端就可以省去再检查文件了;
r4 = true;
}
var r5 = checkEmpty('#description', '#errDescription');
if (r1 && r2 && r3 && r4 && r5){
return true;
}else{
return false;
}
}
// <!--jQUery页面就绪函数,作用是整个html被解析后,来执行这个函数的代码,相当于是一个页面初始化函数;;以前在学习jQuery的时候接触过-->
$(function(){
// $("#category"):是jQuery选择器;执行时机:在html被解释完了之后,才会被执行;然后,jQUery是JavaScript这个浏览器脚本语言的小框架,所以这个肯定是在浏览器上执行的;
// ${painting.category}:是el表达式;执行时机:JSP渲染的时候,在服务器端生成的;
// jQuery的val()方法:可以根据传入的值,根据传入的值,自动把与之匹配的选项进行选中;
$("#category").val(${painting.category});
})
//
function selectPreview(){
checkFile("#painting","#errPainting");// 调用validation.js的方法,检测文件
$("#preview").hide();//当选择一个新的图片后,需要把圆形的那个显示原先旧的图片的<img>给隐藏,这个是出于用户体验的优化
$("#isPreviewModified").val(1);//即如果选择新的文件后,将这个的值设置1
}
</script>
</head>
<body>
<div class="container">
<fieldset>
<legend>作品更新</legend>
<form action="[这里写更新URL]" method="post"
autocomplete="off" enctype="multipart/form-data"
onsubmit = "return checkSubmit()">
<ul class="ulform">
<li>
<span>油画名称</span>
<span id="errPname"></span>
<input id="pname" name="pname" onblur="checkEmpty('#pname','#errPname')" value="${painting.pname}"/>
</li>
<li>
<span>油画类型</span>
<span id="errCategory"></span>
<select id="category" name="category" onchange="checkCategory('#category','#errCategory')">
<option value="-1">请选择油画类型</option>
<option value="1">现实主义</option>
<option value="2">抽象主义</option>
</select>
</li>
<li>
<span>油画价格</span>
<span id="errPrice"></span>
<input id="price" name="price" onblur="checkPrice('#price','#errPrice')" value="${painting.price}"/>
</li>
<li>
<span>作品预览</span>
<input type="hidden" id="isPreviewModified" name="isPreviewModified" value="0">
<span id="errPainting"></span><br/>
<img id="preview" src="${painting.preview }" style="width:361px;height:240px"/><br/>
<input id="painting" name="painting" type="file" style="padding-left:0px;" accept="image/*" onchange="selectPreview()"/>
</li>
<li>
<span>详细描述</span>
<span id="errDescription"></span>
<textarea
id="description" name="description"
onblur="checkEmpty('#description','#errDescription')"
>${painting.description }</textarea>
</li>
<li style="text-align: center;">
<input type="hidden" id="id" name="id" value="${paintint.id}">
<button type="submit" class="btn-button">提交表单</button>
</li>
</ul>
</form>
</fieldset>
</div>
</body>
</html>
update.jsp几点说明:
(1)利用隐藏域设置id:作为唯一标号,提示后端程序,要更新的是哪条数据;
(2)图片部分 (这儿是核心难点重点!!!!!!!!!!!!!!!!!!!!)
即,上面两张图只是为了说明:【type=file的input表单项】当上传文件的时候,可以获取文件名,而且这个文件名可以在后端程序中获取!!!!!!!!!!!!
程序说明:
……………………………………………………
然后,在前台的update.jsp准备好了之后,设置form表单提交地址,并在后台接受这个提交请求
……………………………………………………
然后,View准备好了,Model准备好了,编写Controller部分
ManagementController:Controller类
这儿主要是update()方法;
package com.imooc.mgallery.controller;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.UUID;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import com.imooc.mgallery.entity.Painting;
import com.imooc.mgallery.service.PaintingService;
import com.imooc.mgallery.utils.PageModel;
/**
* 后台管理功能Controller;
* 后台系统,所需要的增,删,改,查的操作,都在这一个Controller类中完成;
* Servlet implementation class ManagementController
*/
@WebServlet("/management")
public class ManagementController extends HttpServlet {
private static final long serialVersionUID = 1L;
// 创建PaintingService对象;;
// 即无论是前台系统的PaintingController,还是后台系统的ManagementController都调用PaintingService中提供的方法;
private PaintingService paintingService = new PaintingService();
/**
* @see HttpServlet#HttpServlet()
*/
public ManagementController() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 设置请求体中的字符集编码方式;;;
// get请求没有请求体,所以,这个语句是为doPost()方法中执行doGet(request,response)后,跳转过来的post请求来设置的;
// 即这条代码是为doPost()来进行服务的;
request.setCharacterEncoding("UTF-8");
// 设置响应的字符集编码方式
response.setContentType("text/html;charset=utf-8");
String method = request.getParameter("method");
if(method.equals("list")) { // 当前台传入的method参数值为“list”的时候,代表是分页请求,调用定义的list方法;
this.list(request,response); // 然后,将分页处理的代码写在list方法中就可以了;
}else if(method.equals("delete")) { // 当method参数值为“delete”时,表示是删除请求,调用定义的delete方法;
this.delete(request, response);
}else if(method.equals("show_create")) {
// method参数为“show_create”,表示是新增;调用新增的方法,跳转到create.jsp
this.showCreatePage(request, response);
}else if(method.equals("create")) {
this.create(request, response);
}else if(method.equals("show_update")) {
// method参数为“show_update”,表示是修改;调用修改的方法,跳转到update.jsp
this.showUpdatePage(request,response);
}else if(method.equals("update")) {
this.update(request, response);
}
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response); // doPost调用了doGet()方法,所以,把逻辑代码都写在doGet方法中就可以了;
}
/**
*
* @param request
* @param response
* @throws IOException
* @throws ServletException
*/
private void list(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String p = request.getParameter("p");
String r = request.getParameter("r");
if(p==null) {
p = "1";
}
if(r==null) {
r = "6";
}
PageModel pageModel = paintingService.pagination(Integer.parseInt(p), Integer.parseInt(r));
request.setAttribute("pageModel", pageModel);
request.getRequestDispatcher("/WEB-INF/jsp/list.jsp").forward(request, response);
}
private void delete(HttpServletRequest request, HttpServletResponse response) {
}
/**
* 显示【新增】页面;这个方法,是一个纯粹的入口;跳转到create.jsp前端页面
* @param request
* @param response
* @throws ServletException
* @throws IOException
*/
private void showCreatePage(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.getRequestDispatcher("/WEB-INF/jsp/create.jsp").forward(request, response);
}
/**
* 新增油画数据;; 处理来自于create.jsp提交过来的表单数据
* @param request
* @param response
* @throws ServletException
* @throws IOException
* @throws FileUploadException
*/
private void create(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
// 使用FileUpload需要按照以下步骤
// 1.初始化FileUpload组件
FileItemFactory factory = new DiskFileItemFactory();
/**
* FileItemFactory :将前端表单的数据转化为一个一个的FileItem对象;即用于数据的转换;
* ServletFileUpload :为FileUpload组件提供凝Java web层面上的HTTP请求解析的功能;即提供对web的支持;
*/
ServletFileUpload sf = new ServletFileUpload(factory);
// 2.遍历所有的FileItem
try {
// 对原有的request请求进行解析;这个方法执行后,就会将当前请求中每一个提交来的表单数据转化为一个一个的FileItem对象;
// 并且方法的返回值是一个List
// 这个会抛出“FileUploadException”,这儿建议对异常进行捕捉而不是抛出;
// 这个“FileUploadException”异常抛出的时机是:当对form表单进行解析时候,发现当前表单的编码格式并不是【enctype="multipart/form-data"】时候,就会抛出“FileUploadException”异常
List<FileItem> formData = sf.parseRequest(request);
Painting painting = new Painting();
for(FileItem fi:formData) {
// FileItem对象的isFormField()方法可以判断:这个FileItem对象是一个普通输入项,还是一个文件上传框;
// 如果FileItem对象是一个普通输入项,该FileItem对象调用isFormField()方法,返回true;
// 如果FileItem对象是一个文件上传框,该FileItem对象调用isFormField()方法,返回false;
if(fi.isFormField()) {
// 这个输出,只是开发阶段的测试用,后续会有其他处理方式;;;
switch (fi.getFieldName()) {
case "pname":
// 当请求中是一个form,而且这个form的编码方式是“multipart/form-data”时候,在doGet()方法中的【request.setCharacterEncoding("UTF-8");】会失效;;;所以这儿在获取请求中(表单的)参数值的时候,需要设置下编码方式
painting.setPname(fi.getString("UTF-8"));
break;
case "category":
painting.setCategory(Integer.parseInt(fi.getString("UTF-8")));
break;
case "price":
painting.setPrice(Integer.parseInt(fi.getString("UTF-8")));
break;
case "description":
painting.setDescription(fi.getString("UTF-8"));
break;
default:
break;
}
//System.out.println("普通输入项"+fi.getFieldName()+":"+fi.getString("UTF-8"));
}else {
// 这个输出,只是开发阶段的测试用,后续会有其他处理方式;;;
System.out.println("文件上传框"+fi.getFieldName());
// 3.将前端上传的文件,保存到服务器某个目录中
// getRealPath()方法:获取Tomcat在实际运行环境中,某个对应的目录在(部署了该Tomcat)服务器上的物理地址;
String path = request.getServletContext().getRealPath("/upload");
System.out.println(path);
//String fileName = "test.jpg";
// UUID:根据计算机(实际中就是Tomcat部署的服务器)的本地特性,根据当前时间,计算机网卡的mac地址,或
// 者其他的,诸如此类独特的特性,生成一个全世界唯一的字符串;
// UUID类是Java内置的,可以直接使用;调用randomUUID()就可以得到随机字符串;
// 以这个随机字符串作为文件名,根本不用担心重名的问题;
String fileName = UUID.randomUUID().toString();
// 得到文件扩展名:getName():获取文件的名称;然后substring()获取文件的扩展名
String suffix = fi.getName().substring(fi.getName().lastIndexOf("."));
fi.write(new File(path,fileName+suffix));
painting.setPreview("/upload/"+fileName + suffix);// 设置油画地址
}
}
paintingService.create(painting);
// 由此,后台部分,油画的新增操作已经完成了;;;;然后可以再跳转到油画列表页面,对数据进行展示
// 使用响应重定向,调回到油画列表页面;
// 上面【完成新增数据】和【显示列表页】,这两者并没有明显的直接关系;;;【显示列表页】仅仅是让浏览器跳转到一个全新的功能上,对于此类场景就可以使用响应重定向;
// 如果此时,【新增完数据 】之后,不是显示列表页,而是弹出另外一个页面,进行新增数据以后的后续操作,这个操作和前面的新增数据是紧密联系的,此时就需要使用请求转发,将当前的请求转给下面的功能,继续进行操作;
response.sendRedirect("/management?method=list");
} catch (FileUploadException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch(Exception e) {
e.printStackTrace();
}
}
/**
* 显示【修改】页面;这个方法,是一个纯粹的入口;跳转到update.jsp前端页面
* @param request
* @param response
* @throws IOException
* @throws ServletException
*/
public void showUpdatePage(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
String id = request.getParameter("id");// 首先获取前台传递过来的id号
Painting painting = paintingService.findById(Integer.parseInt(id)); //调动Model层的方法,获取根据id查询的painting对象
request.setAttribute("painting", painting);// 将查询得到的painting对象,设置成request对象的参数;方便前端获取
request.getRequestDispatcher("/WEB-INF/jsp/update.jsp").forward(request, response);
}
/**
*
* @param request
* @param response
*/
private void update(HttpServletRequest request, HttpServletResponse response) {
FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload sf = new ServletFileUpload(factory);
int isPriviewModified = 0; // 是否上传新文件的标识符
Painting painting = new Painting();
try {
List<FileItem> formData = sf.parseRequest(request);
for(FileItem fi:formData) {
if(fi.isFormField()) {
switch (fi.getFieldName()) {
case "id":
painting.setId(Integer.parseInt(fi.getString("UTF-8")));
break;
case "pname":
// 当请求中是一个form,而且这个form的编码方式是“multipart/form-data”时候,在doGet()方法中的【request.setCharacterEncoding("UTF-8");】会失效;;;所以这儿在获取请求中(表单的)参数值的时候,需要设置下编码方式
painting.setPname(fi.getString("UTF-8"));
break;
case "category":
painting.setCategory(Integer.parseInt(fi.getString("UTF-8")));
break;
case "price":
painting.setPrice(Integer.parseInt(fi.getString("UTF-8")));
break;
case "isPreviewModified":
isPriviewModified = Integer.parseInt(fi.getString("UTF-8"));
break;
case "description":
painting.setDescription(fi.getString("UTF-8"));
break;
default:
break;
}
}else if(isPriviewModified == 1) {// 只有当其上传了新的图片文件,formData中才会有文件项,也才会执行到这个else语句
String path = request.getServletContext().getRealPath("/upload");
String fileName = UUID.randomUUID().toString();
String suffix = fi.getName().substring(fi.getName().lastIndexOf("."));
fi.write(new File(path,fileName+suffix));
painting.setPreview("/upload/"+fileName + suffix);// 设置油画地址
}
}
paintingService.update(painting, isPriviewModified);
response.sendRedirect("/management?method=list");
} catch (FileUploadException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
ManagementController类几点说明:
(1)update.jsp这个前端页面跳转到这儿,并且参数method=update;
(2)看update()方法的代码:在编写的时候,就感觉,为了实现同一个需求,本来就可以有不同的编码方式和不同的具体实现逻辑;在安全高效的情况下,看自己习惯爱好吧。。。。。