Java Web 图片管理与分享系统(Struts2+Hibernate+JSP实现)

100 阅读8分钟

本示例是使用JavaWeb技术实现一个简单的图片管理与分享系统,其中主要功能如下:

  • 用户分类浏览系统中的图片缩略图
  • 用户查看单张图片的详细信息,图片下载
  • 用户查看一个分类内的所有图片缩略图
  • 用户使用关键字进行模糊搜索
  • 管理员登录
  • 管理员拥有普通用户的所有功能,同时能够实现图片的删除

使用的主要技术有:
JavaEE、JSP、Struts2、Hibernate、JavaBean

本项目开发环境为:

  • Intellij IDEA 2016.3
  • Tomcat 8
  • JDK 1.8
  • MySQL 5.5

\

由于本人水平有限,该工程也只是我一边学习一边开发的一个用于课程作业的项目,所以其中还有很多不完善的地方,难免在某些情况下会有些bug,希望大家能够谅解。其实这个作业做了也过了快一个月了,很久没有更新博客了,所以今天这里记录下来,希望能够给其他同学一个参考和帮助,如果有什么建议或者问题也欢迎在博客下留言~

\

\

完整工程下载地址(包含网页截图和数据库建表sql文件):


download.csdn.net/detail/qq_2…\

**
**

**
**

**
**

简单的界面展示:

**
**

1.主页界面index.jsp:

**
**

**
**

**
**

**
**

2.图片详情页面item_preview.jsp:

**
**

**
**

**
**

**
**

3. 图片分类浏览页面AllcartoonPic.jsp/SearchResult.jsp:

**
**

**
**

4.图片上传界面contact.jsp:

**
**

\

为了方便大家建立数据库,这里也放上数据库的数据字典截图:

\

\

**
**

核心代码介绍:

**
**

对于主界面显示的index.jsp 主要就是调用Javabean(QueryAllPhoto)来从后台查询数据,然后返回一个ArrayList(person_pic_list),列表里面的每一个元素强制转换成一个PhotoInfoEntity对象之后,就可以取出每张图片的各种信息,主要代码片段如下:

其中index.jsp页面会有三个这种div,每一个div里显示八张该类别的图片的缩略图。其他的div里只是String category更换成相应的值就好了。


<div class="row">
                    <div class="col-xs-12 col-md-12">
                        <div class="item_container">
                            <% String category = "人物图片";
                                QueryAllPhoto query = new QueryAllPhoto();
                                ArrayList person_pic_list = query.QueryByExt(category);

                            %>
                            <%
                                for (int i = 0; i < 8 && i < person_pic_list.size(); i++) {
                                    PhotoInfoEntity tem = (PhotoInfoEntity) person_pic_list.get(i);
                            %>
<!--一张图片的信息===============================================================================================================-->
                            <div class="item">
                                <a href="item_preview.jsp?id=<%=tem.getId()%>&dir=<%=tem.getDir()%>&ext=<%=tem.getExt()%>&realName=<%=tem.getRelName()%>&ip=<%=tem.getIp()%>&dt=<%=tem.getDt()%>&info=<%=tem.getInfo()%>"
                                   class="thumbnail">
                                    <img src="<%=tem.getDir()%>" alt="377 blue tech">
                                    <p><%=tem.getRelName()%>
                                    </p>
                                </a>
                            </div>
                            <%
                                }
                            %>
                            
                        </div>
                    </div>
</div>

每个jsp页面的查询功能是由下面这一小段代码实现:

通过post 方法将keyword信息提交到SearchResult.jsp页面。

<form action="SearchResult.jsp" method="post" class="navbar-form navbar-right" role="search">
                <div class="form-group">
                    <input type="text" class="form-control" name="keyword" id="keyword" placeholder="图片查询">
                </div>
                <button type="submit" class="btn btn-default">查询</button>
</form>


\

在SearchResult.jsp页面,使用String keyword = request.getParameter("keyword");得到需要查询的图片关键字信息,然后同样调用后台的JavaBean实现查询,并将结果返回到一个ArrayList中。然后和index.jsp一样将一张张的图片显示出来。

核心代码片段如下:


 <div class="row">
                    <div class="col-xs-12 col-md-12">
                        <div class="item_container">
                            <% String keyword = request.getParameter("keyword");
                                QueryAllPhoto query = new QueryAllPhoto();
                                ArrayList pic_list = query.QueryByKeyword(keyword);


                            %>


                            <%
                                if (pic_list.size() == 0) {
                            %>
                            <div class="item">
                                <p><b>查询不到相关的图片,请更换关键字再次尝试。</b></p>
                            </div>
                            <% } else {
                                for (int i = 0; i < pic_list.size(); i++) {
                                    PhotoInfoEntity tem = (PhotoInfoEntity) pic_list.get(i);
                            %>
                           <!-- 一张图片的信息======================================-->
                            <div class="item">
                                <a href="item_preview.jsp?id=<%=tem.getId()%>&dir=<%=tem.getDir()%>&ext=<%=tem.getExt()%>&realName=<%=tem.getRelName()%>&ip=<%=tem.getIp()%>&dt=<%=tem.getDt()%>&info=<%=tem.getInfo()%>"
                                   class="thumbnail">
                                    <img src="<%=tem.getDir()%>" alt="377 blue tech">
                                    <p><%=tem.getRelName()%>
                                    </p>
                                </a>
                            </div>


                            <%
                                    }
                                }
                            %>
                       </div>
                    </div>
</div>

**
**

在index.jsp界面点击一张图片的缩略图会自动跳转到该图片的详情页,实现思路是点击图片缩略图之后会自动跳转到item_preview.jsp页面,由于在URL中存储了图片的相关信息,所以在item_preview.jsp页面直接使用request.getparameter()方法就能够得到该图片的各种详细信息。然后在直接显示出来就行。


 <a href="item_preview.jsp?id=<%=tem.getId()%>&dir=<%=tem.getDir()%>&ext=<%=tem.getExt()%>&realName=<%=tem.getRelName()%>&ip=<%=tem.getIp()%>&dt=<%=tem.getDt()%>&info=<%=tem.getInfo()%>"

\

实际上,我的这种实现方式并不科学,我这种相当于在index.jsp页面就已经把一张图片的各种信息都查询出来了,然后只是没有显示出来而已,然后在图片详情页再直接显示出来,这样的话其实在图片数量较多或图片较大的情况下,index.jsp页面的加载将会非常的缓慢。

较科学的实现方式是,在index.jsp页面只查询图片的标签信息、图片编号、图片的存储路径,然后在item_preview.jsp页面根据图片的编号信息再去查询一次数据库得到图片的完整详情。

\

\

前台的代码还有一个需要说明的地方就是管理员的登录,使用的是Struts2,框架来实现登录信息的处理的,主要代码片度如下:

form表单中使用post方式将表单信息提交到CheckLogin.action这个action来处理。Struts2框架会捕捉到这个请求并实例化相应的action类来进行相应的处理。

<form method="post" action="CheckLogin.action">
						<div class="panel">
							<div class="panel-head"><strong>管理员登录</strong></div>
							<div class="panel-body" style="padding:30px;">
								<div class="form-group">
									<div class="field field-icon-right">
										<input type="text" class="input" name="admin" placeholder="登录账号"  />
										<span class="icon icon-user"></span>
									</div>
								</div>
								<div class="form-group">
									<div class="field field-icon-right">
										<input type="password" class="input" name="password" placeholder="登录密码" />
										<span class="icon icon-key"></span>
									</div>
								</div>

							</div>
							<div class="panel-foot text-center">
								<button class="button button-block bg-main text-big">立即登录</button>
							</div>
						</div>
</form>


\

上传图片的contact.jsp也是使用Struts2框架来捕获上传的图片信息和请求,主要代码如下:

表单通过post方式将表单信息提交到UploadPic这个action进行处理。

<form role="form" enctype="multipart/form-data" method="post" action="UploadPic">
				<div class="row">
					<div class="col-md-5">
						<div class="form-group">
							<input name="pic_name" type="text" class="form-control" id="pic_name" placeholder="图片名称">
						</div>
						<div class="form-group">
							<select name="pic_ext" type="text" class="form-control" id="pic_ext" placeholder="图片类型">
								<option>卡通图片</option>
								<option>风景图片</option>
								<option>人物图片</option>
							</select>
						</div>
						<div class="form-group">
							<input type="file" name="pic_data" id="pic_data" class="form-control"/>
						</div>
					</div> 
					<div class="col-md-7">
						<div class="form-group">
						  	<textarea name="pic_info" rows="6" class="form-control" id="pic_info" placeholder="图片描述信息..."></textarea><br>
							<button type="submit" class="btn btn-primary">确认上传</button>
						</div>
					</div>
				</div> 
</form>

\

**
**

下面介绍Struts2的配置文件:

以第一个action为例,name属性是表示这个action的名称为UploadPic(也就是jsp中form表单里填写的那个),

class属性是指定执行该请求的实体类是cn.hncu.Action包下的UploadAction.java这个类,

method属性表示调用UploadAction.java这个类中的ajaxGetImage()这个方法来具体处理,

result标签表示如果ajaxGetImage()的返回值是字符串“Successful”那么就跳转到index.jsp,

如果ajaxGetImage()的返回值是字符串“failed”那么跳转到contact.jsp。

\

下面的两个action也是以此类推。

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
        "http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>

    <package name="struts2" namespace="/" extends="struts-default">
        <action name="UploadPic" class="cn.hncu.Action.UploadAction" method="ajaxGetImage">
            <result name="successful">index.jsp</result>
            <result name="failed">contact.jsp</result>
        </action>

        <action name="DeletePic" class="cn.hncu.Action.DeleteAction" method="DeleteImage">
            <result name="successful">index.jsp</result>
            <result name="failed">item_preview.jsp</result>
        </action>

        <action name="CheckLogin" class="cn.hncu.Action.CheckLoginAction" method="check">
            <result name="successful">index.jsp</result>
            <result name="failed">AdminLogin.jsp</result>
        </action>
    </package>
</struts>



接下来是要实现UPloadAction类和其中的方法:

Struts2框架会自动实例化一个UploadAction对象,然后将jsp表单中的属性使用setter和getter方法封装到这个对象的同名属性中,然后自动调用配置文件中指定的ajaxGetImage()方法。

package cn.hncu.Action;

import cn.hncu.Dao.PhotoInfoEntity;
import org.apache.struts2.ServletActionContext;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * Created by 32706 on 2017/4/19.
 */
public class UploadAction {
    private File pic_data;//Ajax获取图片文件,与控件type=File中的name属性一样
    private String pic_name;//Ajax获取图片文件名称,相应的name属性名称+FileName
    private String pic_ext;//图片类别
    private String pic_info;//图片描述信息

    /**
     * -----------相应的get和set方法----------------
     **/
    public File getPic_data() {
        return pic_data;
    }

    public void setPic_data(File pic_data) {
        this.pic_data = pic_data;
    }

    public String getPic_name() {
        return pic_name;
    }

    public void setPic_name(String pic_name) {
        this.pic_name = pic_name;
    }

    public String getPic_ext() {
        return pic_ext;
    }

    public void setPic_ext(String pic_ext) {
        this.pic_ext = pic_ext;
    }

    public String getPic_info() {
        return pic_info;
    }

    public void setPic_info(String pic_info) {
        this.pic_info = pic_info;
    }

    /**
     * 通过Ajax获取图片信息
     *
     * @return
     * @throws IOException
     */
    public String ajaxGetImage() throws Exception {

        HttpServletResponse response = ServletActionContext.getResponse();
        response.setContentType("text/plain");
        response.setCharacterEncoding("utf-8");
        if (pic_data != null) {
            String fileName = pic_data.getName();
            String savePath = ServletActionContext.getServletContext().getRealPath("/");

            String finalPath = save_pic_on_disk(pic_data, savePath, fileName);
            if (finalPath != null)//将图片存储到本地文件
            {
                if (upload_info_to_database(finalPath, pic_ext, pic_info, "administrator", pic_name))//调用hibernate将数据插入数据库
                {
                    response.getWriter().print("图片上传成功!");//把相应的地址放到前台解析,通过#符号分割
                    return "successful";
                } else {
                    System.out.println("调用hibernate持久化过程出错");
                    response.getWriter().print("图片上传失败!====调用hibernate持久化过程出错");
                    return "failed";
                }
            } else {
                response.getWriter().print("图片上传失败!====保存到本地失败");
                return "failed";
            }


        } else {
            System.out.println("图片数据为空=====================");
            response.getWriter().print("图片上传失败!");
            return "failed";
        }

    }


    private boolean upload_info_to_database(String savePath, String pic_ext, String info, String ip, String pic_name) {
        try {
            java.util.Date date = new java.util.Date();
            DateFormat format = new SimpleDateFormat("yyyy-MM-dd/HH:mm:ss");
            String time = format.format(date);//得到完成订单的时间
            DateFormat format1 = new SimpleDateFormat("yyyyMMddHHmmss");
            String pic_id = format1.format(date) + (int) (Math.random() * 1000);

            Configuration conf = new Configuration().configure();
            SessionFactory sf = conf.buildSessionFactory();
            //Session session = sf.openSession();
            Session  session=sf.getCurrentSession();
            PhotoInfoEntity photo = new PhotoInfoEntity();
            photo.setDir(savePath);
            photo.setDt(time);
            photo.setExt(pic_ext);
            photo.setId(pic_id);
            photo.setInfo(info);
            photo.setIp(ip);
            photo.setRelName(pic_name);

            Transaction tran = session.beginTransaction();
            session.save(photo);
            tran.commit();
            session.close();
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }


    private String save_pic_on_disk(File data, String savePath, String fileName) {
        String rt = "";
        java.util.Date date = new java.util.Date();
        DateFormat format = new SimpleDateFormat("yyyyMMdd");
        String time = format.format(date);//得到完成订单的时间
        System.out.println(savePath);
        String dir_url = "uploadImage/" + time + "/";
        String realFileName=new Date().getTime()+fileName+".jpg";
        String realPath=savePath+dir_url+realFileName;

        System.out.println("最终保存的文件路径为======" + realPath);

        try {

            File file = new File(savePath + dir_url);//每天的图片放在一个文件夹里
            //如果文件夹不存在则创建
            if (!file.exists() && !file.isDirectory()) {
                System.out.println(dir_url + "文件夹不存在,新建一个");
                file.mkdir();
            }

            FileOutputStream out=new FileOutputStream(realPath);
            FileInputStream in=new FileInputStream(data);
            byte[]buffer=new byte[1024];
            int len=0;
            while((len=in.read(buffer))!=-1){
                out.write(buffer,0,len);

            }
            out.flush();
            out.close();
            in.close();
            return dir_url+realFileName;

        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("保存文件到文件中出错=================Database.save_picture_in_file");
            return null;
        }
    }
  public static void main(String arg[]) {
    }
}


\

\

另外两个Action的实现是类似的,这里限于版面就不在赘述了,大家可以下载完整的工程文件查看。(博客底部和顶部有下载链接)




介绍到这里还有一个前台使用的JavaBean没有介绍到,这个就是QueryAllphoto.java:

其中有两个方法,一个是QueryByExt()方法,表示根据图片的类别来查询,在图片分类浏览和index.jsp页面会使用到。

第二个方法是QueryByKeyword(),是使用图片标签的关键字来进行查询。

\

package cn.hncu.Dao;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.query.Query;

import java.util.ArrayList;
import java.util.List;


public class QueryAllPhoto {


    public  ArrayList QueryByExt(String category) {
        ArrayList rt=new ArrayList();
        Configuration configuration=new Configuration().configure();
        SessionFactory sessionFactory=configuration.buildSessionFactory();
        Session session=sessionFactory.openSession();

        String hql="from PhotoInfoEntity where ext='"+category+"'";
        System.out.println(hql+"========================================================================");

        Query query=session.createQuery(hql);
        List list=query.list();
        for(int i=0;i<list.size();i++)
        {
            PhotoInfoEntity tem=(PhotoInfoEntity)list.get(i);
            rt.add(tem);
        }
        System.out.println(rt.size()+"大小========================================================================");
        return  rt;
    }



    public  ArrayList QueryByKeyword(String keyword) {
        ArrayList rt=new ArrayList();
        Configuration configuration=new Configuration().configure();
        SessionFactory sessionFactory=configuration.buildSessionFactory();
        Session session=sessionFactory.openSession();

        String hql="from PhotoInfoEntity where relName  like '%"+keyword+"%'";
        System.out.println(hql+"========================================================================");

        Query query=session.createQuery(hql);
        List list=query.list();
        for(int i=0;i<list.size();i++)
        {
            PhotoInfoEntity tem=(PhotoInfoEntity)list.get(i);
            rt.add(tem);
        }
        System.out.println(rt.size()+"大小========================================================================");
        return  rt;
    }



    public  static  void main(String arg[])
    {
        QueryAllPhoto q=new QueryAllPhoto();
        ArrayList result=q.QueryByExt("风景图片");

        System.out.println(result.size());

    }

}




在QueryAllPhoto.java中我们调用了Hibernate框架来实现数据的访问和查询等操作,下面就来介绍Hibernate的配置文件hibernate.cfg.xml:

<?xml version='1.0' encoding='utf-8'?>
<!--表明解析本XML文件的DTD文档位置,DTD是Document Type Definition 的缩写,即文档类型的定义,XML解析器使用DTD文档来检查XML文件的合法性。hibernate.sourceforge.net/hibernate-configuration-3.0dtd可以在Hibernate3.1.3软件包中的src\org\hibernate目录中找到此文件-->
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<!--声明Hibernate配置文件的开始-->
<hibernate-configuration>
    <!--表明以下的配置是针对session-factory配置的,SessionFactory是Hibernate中的一个类,这个类主要负责保存HIbernate的配置信息,以及对Session的操作-->
    <session-factory>
        <!--配置数据库的驱动程序,Hibernate在连接数据库时,需要用到数据库的驱动程序-->
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <!--设置数据库的连接url:jdbc:mysql://localhost/hibernate,其中localhost表示mysql服务器名称,此处为本机,    hibernate是数据库名-->
        <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/photo</property>
        <!--连接数据库是用户名-->
	<property name="connection.username">root</property>
        <!--连接数据库是密码-->
	<property name="connection.password">root</property>
        <!--数据库连接池的大小-->
        <property name="hibernate.connection.pool.size">20</property>
        <!--是否在后台显示Hibernate用到的SQL语句,开发时设置为true,便于差错,程序运行时可以在Eclipse的控制台显示Hibernate的执行Sql语句。项目部署后可以设置为false,提高运行效率-->
        <property name="hibernate.show_sql">true </property>
        <!--jdbc.fetch_size是指Hibernate每次从数据库中取出并放到JDBC的Statement中的记录条数。Fetch Size设的越大,读数据库的次数越少,速度越快,Fetch Size越小,读数据库的次数越多,速度越慢-->
        <property name="jdbc.fetch_size">50 </property>
        <!--jdbc.batch_size是指Hibernate批量插入,删除和更新时每次操作的记录数。Batch Size越大,批量操作的向数据库发送Sql的次数越少,速度就越快,同样耗用内存就越大-->
        <property name="jdbc.batch_size">23 </property>
        <!--jdbc.use_scrollable_resultset是否允许Hibernate用JDBC的可滚动的结果集。对分页的结果集。对分页时的设置非常有帮助-->
        <property name="jdbc.use_scrollable_resultset">false </property>
        <!--connection.useUnicode连接数据库时是否使用Unicode编码-->
        <property name="Connection.useUnicode">true </property>
        <!--connection.characterEncoding连接数据库时数据的传输字符集编码方式,最好设置为gbk,用gb2312有的字符不全-->
        <property name="connection.characterEncoding">utf-8</property>

        <!--hibernate.dialect 只是Hibernate使用的数据库方言,就是要用Hibernate连接那种类型的数据库服务器。-->
        <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect </property>
        <mapping resource="cn/hncu/Dao/PhotoInfoEntity.hbm.xml"/>
        <mapping class="cn.hncu.Dao.PhotoInfoEntity"/>
        <mapping class="cn.hncu.Dao.AdminEntity"/>
        <mapping resource="cn/hncu/Dao/AdminEntity.hbm.xml"/>

    </session-factory>
</hibernate-configuration>



为了使Hibernate能够将数据库表和java对象联系起来,我们还需要两个持久化对象类:AdminEntity.java 以及PhotoInfoEntity.java

这两个类在intellij中是可以自动生成的,具体方法可以查看博文:blog.csdn.net/u014520745/…

在eclipse等 IDE中的生成方式请自行百度。

这里就简单介绍下AdminEntity.java:

该类中的每一个属性对应数据库表中的一个属性,然后每个属性会有一个setter和getter方法。

PhotoInfoEntity.java也是类似只是属性会多一些。\

package cn.hncu.Dao;

import javax.persistence.*;

/**
 * Created by 32706 on 2017/4/20.
 */
@Entity
@Table(name = "admin", schema = "photo", catalog = "")
public class AdminEntity {
    private String adminName;
    private String password;

    @Id
    @Column(name = "admin_name")
    public String getAdminName() {
        return adminName;
    }

    public void setAdminName(String adminName) {
        this.adminName = adminName;
    }

    @Basic
    @Column(name = "password")
    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        AdminEntity that = (AdminEntity) o;

        if (adminName != null ? !adminName.equals(that.adminName) : that.adminName != null) return false;
        if (password != null ? !password.equals(that.password) : that.password != null) return false;

        return true;
    }

    @Override
    public int hashCode() {
        int result = adminName != null ? adminName.hashCode() : 0;
        result = 31 * result + (password != null ? password.hashCode() : 0);
        return result;
    }
}




至此整个工程的一些主要核心代码就已经介绍完了,如果需要工程源文件请访问:

download.csdn.net/detail/qq_2…\

\

如有错误和纰漏请多多包含,欢迎在下面留言。
\