JavaWeb-News-文件上传

来源:互联网 发布:外国人对淘宝的评价 编辑:程序博客网 时间:2024/05/16 18:57

话说:

昨天把分页作为礼物送给了自己,今天文件上传和昨天的一气呵成。
昨天的新闻没有上传功能,今天总结下;整体修改还是建立在上一篇分页基础之上。

目标:文件上传

围绕4个问题:


Q1:如何自定义文件名?
Q2: 如何获取文件后缀名?
Q3:如何获取文件存储路径(Web服务器和工程目录下各一份)?
Q4:如何将文件路径要存储到数据库表中的pic字段中?


前期准备:

1)在数据库里面新建一列pic,因为反射机制不能默认为null,所以通通把这一列设置为”images/default.jpg”;
存图片的列需要设置成BLOB、MEDIUMBLOB或LONGBLOB等数据类型
但是一般我们肯定不直接在数据库存图片楼,节省速度。
所以,我们存放图片路径。
update t_news set pic= “images/default.jpg”;

2)为了保证发布新闻界面newsAdd.jsp页面在提交表单的时候,可以提交文件,所以要新增表单属性:enctype=”multipart/form-data”;同时在newsServlet中新增注解:@MultipartConfig。这样就保证了页面添加文件时候,Servlet可以顺利接收到。

newsAdd.jsp

<%--  Created by IntelliJ IDEA.  User: Meice  Date: 2017/10/1  Time: 15:02  To change this template use File | Settings | File Templates.--%><%@ page contentType="text/html;charset=UTF-8" language="java" %><html><head>    <title>发布新闻</title></head><body>    <form action="news.do" method="post" enctype="multipart/form-data">        <%--传递参数的时候,可以直接传参,也可以用隐藏域--%>       <input type="hidden" name="op" value="add"/>        <table>            <tr>                <td>标题</td>               <td><input type="text" name="title"></td>            </tr>            <tr>                <td>作者</td>                <td><input type="text" name="author"></td>            </tr>            <tr>                <td>封面</td>                <td><input type="file" name="pic" alt="尚未提交文件"></td>            </tr>            <tr>                <td colspan="2"><input type="submit" value="发布"></td>            </tr>        </table>    </form></body></html>

以上新增了封面这一行,结果是这样的:

这里写图片描述

好!准备工作到此结束,正式开始搞定4个问题。

Q1:如何自定义文件名?

为避免用户上传文件名相同,所以我们要按照自己规则来重命名文件,类似QQ截图那样。
同样,我们也作为一个工具类,封装成方法getFileName()

public static String getFileName(String suffix) {    SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");    String now = sdf.format(new Date());    return "news"+now+suffix;}

效果是这样的:news20171015171838.png;这样也就搞定了文件前缀名。

//获取文件File;但是用户上传的文件如何获取呢?

 Part part = req.getPart("pic"); part.write("F:\\enheng.exe");String header =   part.getHeader("content-disposition");

part是个接口,通过part的getHeader()方法可以获取的一个key-value的一串名字:类似下面这样:form-data; name=”pic”; filename=”02_BaseDao再设计.exe”
我们需要的是filename,所以通过截取获得后缀名。(前办部分我们按照时间戳自定义,避免用户传入文件名称相同)

这里写图片描述

这里写图片描述

Q2:如何获取文件后缀名?

前面header就是一个包含文件完整名称的key-value键值队,截取出后缀名即可。为便于后面运用,我们封装为一个方法getSuffix()

//定义获取文件后缀的方法getSuffix()private String getSuffix(String filename){    //详细过程看main()方法测试    String subStr = filename.substring(filename.indexOf("filename"),filename.lastIndexOf("\""));    subStr = subStr.substring(subStr.indexOf("\"")+1);    subStr = subStr.substring(subStr.indexOf("."));    return subStr;}

这样,不论你传输什么文件,后缀名都可以搞定了。jpg,jpeg,gif都可以,视频也可以的,只不过,页面不好显示。

Q3:如何获取文件存储路径(Web服务器和工程目录下各一份)?

为什么要获取绝对路径呢?因为不同浏览器有的支持绝对路径,有的不支持。
要是再Linux中就好了。

项目路径,直接可以查看,我们定义为proPath
项目在Tomcat服务器部署路径,通过getRealPath()方法可以获取,定义为realPath

  String proPath ="D:\\Users\\Administrator\\IdeaProjects\\Meice_idea_utimate\\JavaWeb_Servlet_Paging\\web\\images";//获取项目在服务器部署后的真实路径;服务器也会迁移啊。Linux就不用了在部署Web服务器对应Images目录下再次写入一次String realPath = req.getSession().getServletContext().getRealPath("images");

Q4:如何将文件路径要存储到数据库表中的pic字段中?

    //相对路径用于存储表中pic字段String filename =  FileUploadUtil.getFileName(getSuffix(header));String relPath = "images/"+ filename;    //写入到项目文件中    part.write(proPath+"/"+filename);.....news.setPic(relPath);

同时,我们只需要稍作修改这几个地方,整个图片上传就搞定啦!

1、news.setPic(relPath); 为pic字段设置属性,路径就是images/我们自定义的文件名。一旦用户点击上传,项目路径下会按照我们的命名规则产生新的文件:类似这样:news20171015205739.jpg
项目一旦部署,会在工程对应的Web服务器端再次生成这个文件。

2、修改newsUpdate2()方法,创建对象的时候,新增pic属性即可

//法2:封装发布新闻的方法(前后对比明显吧!)public int newsAdd2(News news){    String sql = "insert into t_news (title,author,pic) values (?,?,?)";    Object[] params = {news.getTitle(),news.getAuthor(),news.getPic()};   return CUD(sql,params);}

3、最后,在显示页面newsShow.jsp,显示图片。

<td align="center"><img src="${news.pic}" width="60px" height="60px"></td>

4、调试过程,可能报一下错误:

这里写图片描述

这个时候,我在部署后的路径下找到了上传的图片;但是在工程images下面没有找到。
奇怪的是,这里报错是从C:根目录下开始找的……;
这里是正常的,在IDEA里面,就是会自己在生成一个路径。经过排查,发现不能同时给两个位置写入文件。

  //写入到项目文件中    part.write(proPath+"/"+filename);//写入到Tomcat服务器中   // part.write(realPath+"/"+filename);

只有写入项目中,然后重新部署,刷新就可以显示啦!



以下是完整代码:

主要修改的就是newsServlet、我们自己定义的工具类FileUploadUitl(重命名文件)和getSuffix()方法(获取文件后缀名)

实体类News

package com.hmc.jdbc.news.model;public class News {    private   int id;    private   String title;    private String author;    private String pic;    public News() {    }    public News(int id, String title, String author) {        this.id = id;        this.title = title;        this.author = author;    }    public News(int id, String title, String author, String pic) {        this.id = id;        this.title = title;        this.author = author;        this.pic = pic;    }    //没有2个参数的构造方法,我自己就造一个出来;因为增加新闻不需要考虑ID,对于客户来说。    public News(String title, String author) {        this.title = title;        this.author = author;    }    public int getId() {        return id;    }    public void setId(int id) {        this.id = id;    }    public String getTitle() {        return title;    }    public void setTitle(String title) {        this.title = title;    }    public String getAuthor() {        return author;    }    public void setAuthor(String author) {        this.author = author;    }    public String getPic() {        return pic;    }    public void setPic(String pic) {        this.pic = pic;    }    @Override    public String toString() {        return "News{" +                "id=" + id +                ", title='" + title + '\'' +                ", author='" + author + '\'' +                ", pic='" + pic + '\'' +                '}';    }}

以上仅仅增加了pic这个属性,生成了set(),get()方法。

NewsServlet

package com.hmc.jdbc.news.servlet;import com.hmc.jdbc.news.dao.BaseDao;import com.hmc.jdbc.news.dao.NewsDao;import com.hmc.jdbc.news.model.News;import com.hmc.jdbc.news.model.Pager;import com.hmc.jdbc.news.util.FileUploadUtil;import com.hmc.jdbc.news.util.StringConvertUtil;import javax.servlet.ServletException;import javax.servlet.annotation.MultipartConfig;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.Part;import java.io.IOException;import java.sql.Connection;import java.util.List;/** * User:Meice * 2017/10/5 */@WebServlet(urlPatterns = "/news.do")@MultipartConfigpublic class NewsServlet extends BaseServlet {    NewsDao nd = new NewsDao();    BaseDao bd = new BaseDao();        //查(R)        // 未避免代码混乱,把显示新闻列表封装成方法;这里采用最高级的显示新闻方法listShow3()        private  void list (HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {             String sql = "select * from t_news";            List<News> list =(List<News>) bd.listShow3(sql,News.class,null);            //3 存储到req中            req.setAttribute("list", list);                req.getRequestDispatcher("newsShow.jsp").forward(req, resp);        }        //定义查询分页显示页面的方法pageList()        private void pageList(HttpServletRequest req,HttpServletResponse resp ) {            //接收参数pageIndex           String strPageIndex = req.getParameter("pageIndex");           String strPageSize = req.getParameter("pageSize");          int pageIndex = StringConvertUtil.getVal(strPageIndex);          int pageSize  = StringConvertUtil.getVal(strPageSize);            //当时转换方法里面如果为null返回的是0            pageIndex = pageIndex ==0?1:pageIndex;            pageSize = pageSize == 0?5:pageSize;            Pager<News> pager = new Pager<>();           //避免最后页会多出来            pager.setCount(nd.count());            pager.setPageIndex(pageIndex);            pager.setPageSize(pageSize);            //调用pageList()方法            pager = nd.pageList(pager);            //存储到req中            req.setAttribute("pager",pager);            //页面跳转            try {                req.getRequestDispatcher("newsShow.jsp").forward(req,resp);            } catch (ServletException e) {                e.printStackTrace();            } catch (IOException e) {                e.printStackTrace();            }        }      //增(C)        private void add(HttpServletRequest req,HttpServletResponse resp) throws ServletException, IOException {        //接受参数        String title =   req.getParameter("title");        String author  = req.getParameter("author");        //获取文件File         Part part = req.getPart("pic");        //获取part头信息        String header =   part.getHeader("content-disposition");        //这个路径是我们项目的images所在路径;在本项目路径下写入一次        String proPath ="D:\\Users\\Administrator\\IdeaProjects\\Meice_idea_utimate\\JavaWeb_Servlet_Paging\\web\\images";        //获取项目在服务器部署后的真实路径;服务器也会迁移啊。Linux就不用了在部署Web服务器对应Images目录下再次写入一次        String realPath = req.getSession().getServletContext().getRealPath("images");        //D:\Users\Administrator\IdeaProjects\Meice_idea_utimate\out\artifacts\JavaWeb_Servlet_Paging_war_exploded\images        //相对路径用于存储表中pic字段        String filename =  FileUploadUtil.getFileName(getSuffix(header));        String relPath = "images/"+ filename;        //写入到项目文件中        part.write(proPath+"/"+filename);        //写入到Tomcat服务器中        // part.write(realPath+"/"+filename);        News news = new News(title,author);        news.setPic(relPath);        int result =  nd.newsAdd2(news);//(写这些方法从后往前写)        if(result > 0) {            req.getRequestDispatcher("news.do?op=pageList").forward(req,resp);        }else {            req.getRequestDispatcher("newsAdd.jsp").forward(req,resp);        }    }        //定义获取文件后缀的方法getSuffix()        private String getSuffix(String filename){        //详细过程看main()方法测试        String subStr = filename.substring(filename.indexOf("filename"),filename.lastIndexOf("\""));        subStr = subStr.substring(subStr.indexOf("\"")+1);        subStr = subStr.substring(subStr.indexOf("."));        return subStr;        }        //改(U)        //显示要修改的新闻        public void changeShow(HttpServletRequest req,HttpServletResponse resp) throws ServletException, IOException {         //接受参数        String strId = req.getParameter("id");        int id = StringConvertUtil.getVal(strId);         News news =  nd.newsPut3(id);         req.setAttribute("news",news);         req.getRequestDispatcher("newsUpdate.jsp").forward(req,resp);        }        //执行修改操作        public void change(HttpServletRequest req,HttpServletResponse resp) throws ServletException, IOException {            //接受参数            String strId = req.getParameter("id");            int id = StringConvertUtil.getVal(strId);            String title = req.getParameter("title");            String author = req.getParameter("author");            News news  = new News(id,title,author);           //调用方法            int result =  nd.newsUpdate2(news);                if(result >0) {                    req.getRequestDispatcher("news.do?op=pageList").forward(req,resp);                }else {                    req.getRequestDispatcher("newsUpdate.jsp").forward(req,resp);                }        }        //删(D)        private void del(HttpServletRequest req,HttpServletResponse resp) throws ServletException, IOException {            //接受参数            String strId = req.getParameter("id");            int id = StringConvertUtil.getVal(strId);          int result =  nd.newsDel2(id);                req.getRequestDispatcher("news.do?op=pageList").forward(req,resp);        }           public static  void main(String[] args) {               //form-data; name="pic"; filename="02_BaseDao再设计.exe"               String str =   "form-data; name=\"pic\"; filename=\"02_BaseDao再设计.exe\"";               System.out.println(str.substring(str.indexOf("filename"),str.lastIndexOf("\"")));               String subStr = str.substring(str.indexOf("filename"),str.lastIndexOf("\""));               //filename="02_BaseDao再设计.exe               subStr = subStr.substring(subStr.indexOf("\"")+1);               System.out.println(subStr);                    //"02_BaseDao再设计.exe  02_BaseDao再设计.exe               subStr = subStr.substring(subStr.indexOf("."));               System.out.println(subStr);               //截取过程如下               /*                   filename="02_BaseDao再设计.exe                     02_BaseDao再设计.exe                     .exe                */           }}

FileUpLoad()工具类

package com.hmc.jdbc.news.util;import java.text.SimpleDateFormat;import java.util.Date;/** * User:Meice * 2017/10/15 */public class FileUploadUtil {    public static String getFileName(String suffix) {        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");        String now = sdf.format(new Date());        return "news"+now+suffix;    }    public static void main(String [] args) {        System.out.println(getFileName(".png"));    }}

newsShow.jsp

<%@ page import="java.util.List" %><%@ page import="java.util.Enumeration" %><%@ page import="com.hmc.jdbc.news.model.News" %><%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %><%--  Created by IntelliJ IDEA.  User: Meice  Date: 2017/10/1  Time: 13:30  To change this template use File | Settings | File Templates.--%><%@ page contentType="text/html;charset=UTF-8" language="java" %><%--如果不用jstl,还是采用JSP嵌套获取--%><%--<%    //本来在页面,我们获取list集合非常简单,${}这样就获取了,但是实际过程中,我们在JSP代码中没发做到用这个来获取    List<News> list =(List<News>) request.getAttribute("list");%>--%><html><head>    <title>Meice的新闻列表</title></head><body>    <h2 align="center">Meice的新闻列表</h2><br/>    <a href="newsAdd.jsp">发布新闻</a>    <table border="1" align="center" width="80%">        <thead>            <tr>                <th>编号</th>                <th>标题</th>                <th>作者</th>                <th>图片</th>                <th>操作</th>            </tr>        </thead>        <tbody>           <%--${news}--%>           <%--这里传过来就是那幅图的场景;现在的问题是我不知道怎么接收这个传递过来的值,直接用EL取出来的是           个List<News>的集合。这边又没法遍历。??           如果不用JSTL,我们用普通的for each,问题是怎么取出这个值。           --%>             <c:forEach var="news" items="${pager.datas}">                    <tr>                        <td align="center">${news.id}</td>                        <td align="center">${news.title}</td>                        <td align="center">${news.author}</td>                        <td align="center"><img src="${news.pic}" width="60px" height="60px"></td>                        <td align="center">                            <a href="news.do?op=changeShow&id=${news.id}">修改</a>                            <a href="news.do?op=del&id=${news.id}" onclick="return confirm('真的忍心删我?')">删除</a>                        </td>                    </tr>            </c:forEach>            <tr>                <td colspan="5" align="center">                    <div style="float: left;margin-left: 150px">                       <c:if test="${pager.pageIndex>1}">                           <a href="news.do?op=pageList&pageIndex=1">首页</a> &nbsp;&nbsp;&nbsp;&nbsp;                           <a href="news.do?op=pageList&pageIndex=${pager.pageIndex-1}">上一页</a>&nbsp;&nbsp;&nbsp;&nbsp;                       </c:if>                       <c:forEach var="pn" begin="${pager.start}" end="${pager.end}">                           <c:if test="${pn==pager.pageIndex}">                               ${pn} &nbsp;                           </c:if>                          <c:if test="${pn != pager.pageIndex}">                              <a href="news.do?op=pageList&pageIndex=${pn}">${pn}</a> &nbsp;                          </c:if>                       </c:forEach>                        <%--EL表达式支持运算--%>                        <c:if test="${pager.pageIndex<pager.totalPage}">                            <a href="news.do?op=pageList&pageIndex=${pager.pageIndex+1}">下一页</a>                            &nbsp;&nbsp;&nbsp;&nbsp;                            <a href="news.do?op=pageList&pageIndex=${pager.totalPage}">末页</a>&nbsp;&nbsp;                            ${pager.pageIndex}/${pager.totalPage}                        </c:if>                    </div>                    <%--以下实现页面跳转--%>                    <form action="news.do?op=pageList" method="post" style="float:right;margin-right: 200px" >                        <input type="text" name="pageIndex" style="width: 30px;height: 30px" value="${param.pageIndex}" />                        <select name="pageSize" style="height: 30px">                            <option value="5" ${param.pageSize==5?'selected':''}>5</option>                            <option value="10" ${param.pageSize==10?'selected':''}>10</option>                            <option value="20" ${param.pageSize==20?'selected':''}>20</option>                        </select>                        <input type="submit" value="Go"style="float: right;height: 30px">                    </form>                </td>            </tr>        </tbody>        <tfoot></tfoot>    </table></body></html>

其他代码都和上一篇博客一样。
最终效果图:

这里写图片描述

总结:


主要就是解决文章开头的3个问题。顺着问题找解决方案,目的就很明确。

1、实体类News中封装一个存放图片的属性pic即可,调用方式和其他属性类似;

2、通过request的getPart()方法,返回一个part对象,调用getHeader()方法,根据需要截取文件后缀和重命名文件;

3、part.write()方法可以把我们命名好的文件,存入到工程目录和服务器目录下;

4、把命名好的文件名赋值给变量relPath,传递到页面;

5、修改对应的newsUpdate2()方法,页面newsShow.jsp做对应修改即可。


好了,各位读者,下期见!晚安!

原创粉丝点击