JavaWeb-News-文件上传

话说:

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

目标:文件上传

围绕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")
@MultipartConfig
public 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做对应修改即可。


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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值