背景需求:

 1、给定一个url能够获得图片的内容                                                                                                               

 2、解决个github/博客中插入图片的问题

重要的知识点:

1. 简单的Web服务器设计能力
2. Java 操作 MySQL 数据库
3. 数据库设计
4. Restful 风格 API
5. gson 的使用
6. 强化 HTTP 协议的理解
7. Servlet 的使用
8. 基于 md5 进行校验
9. Postman 工具的使用
10. 软件测试的基本思想和方法

基本框架:

核心就是一个 HTTP 服务器, 提供对图片的增删改查能力。
同时搭配简单的页面辅助完成图片上传/展示。

数据库的设计:

drop database if exists image_system;
create database image_system character set utf8mb4;
use image_system;

drop table if exists `image_table`;
create table `image_table`(image_id int not null primary key auto_increment,
                          image_name varchar(50),
                          size bigint,
                          upload_time varchar(50),
                          md5 varchar(128),
                          content_type varchar(50) comment '图片类型',
                          path varchar(1024) comment '图片所在路径')

上传文件的前端页面:

<html>
<head>
    <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
</head>
<body>
<!--enctype标识了请求体中的数据格式   action=“image”【不加 “/”】  -->
<form method="POST" enctype="multipart/form-data" action="image">
    <table>
        <tr>
            <td>文件上传:</td>
            <td><input type="file" name="uploadImage"/></td>
        </tr>
        <tr>
            <td></td>
            <td><input type="submit" value="上传"/></td>
        </tr>
    </table>
</form>
</body>
</html>

利用Vue组件使用ajax进行前后端的信息交互,并实现图片的上传、查看、删除功能

var app = new Vue({
        el:'#app',
        data: {
            images: [
            ],
            uploadImage: ''
        },
        methods: {
            getImages() {
                $.ajax({
                    url: "image",
                    type: "get",
                    context: this,
                    success: function(data, status) {
                        this.images = data;
                        $("#app").resize();
                    }
                })
            },
            changeImage(event){
                app.uploadImage = event.target.files[0];
            },
            //文件上传
            imageUpload(){
                if(!app.uploadImage) {
                    alert("选择图片后上传");
                    return;
                }
                let data = new FormData();
                data.append("uploadImage", app.uploadImage);
                $.ajax({
                    url: "image",
                    type: "post",
                    processData: false,
                    contentType: false,
                    data: data,
                    // context: this,
                    success: function(data, status) {
                        if(data.ok){
                            app.getImages();
                        } else {
                            alert(data.msg);
                        }
                        // alert("上传成功");
                    },
                    error: function (err, textStatus, throwable) {
                        console.error(err)
                    }
                })
            },
            remove(imageId) {
                $.ajax({
                    url:"image?imageId=" + imageId,
                    type:"delete",
                    context: this,
                    success: function(data, status) {
                        app.getImages();
                        alert("删除成功");
                    }
                })
            }
        },
    });

封装数据库的操作:

使用JDBC驱动来获取数据库的连接:

public class Util {
    //因为创建比较费时,所以就创建一个 够用
    private static final ObjectMapper M = new ObjectMapper();

    //【数据库JDBC】
    //数据库连接池:一个程序用一个数据库连接池,
    //            而这一个数据库连接池  创建的时候 就生成一定数量的连接
    private static final MysqlDataSource DS = new MysqlDataSource();

    static {
        DS.setURL("jdbc:mysql://127.0.0.1:3306/image_system");
       // DS.setUseSSL(true);
        DS.setUser("root");
        DS.setPassword("111111");
        //DS.setUseSSL(false);
        DS.setCharacterEncoding("UTF-8");
    }

    /**
     * json序列化:把一个对象--->json字符串 (Servlet响应输出的body需要json字符串)
     * */
    public static String serialize(Object o){//要既满足list又要满足单个对象
        try {
            return M.writeValueAsString(o);
        } catch (JsonProcessingException e) {
            //e.printStackTrace();
           //序列化和反序列化
            throw new RuntimeException("序列化Java对象失败:"+o, e);
        }
    }
    /**
     * 获取数据库连接
     */
    public static Connection getConnection(){
        try {
            return DS.getConnection();
        } catch (SQLException e) {
            throw new RuntimeException("数据库连接获取失败 ",e);
        }
    }

    /**
     * 统一数据库关闭方法:查询操作的
     */
    public static void close(Connection c, Statement s, ResultSet rs){
        try {
            if(rs != null) rs.close();
            if(s != null) s.close();
            if(c !=null) c.close();
        } catch (SQLException e) {
            throw new RuntimeException("释放数据库资源失败 ",e);
        }
    }

    /**【重载方法】
     * 统一数据库关闭方法:插入、删除、修改 等没有结果集对象
     */
    public static void close(Connection c, Statement s){
        close(c,s,null);
    }
    public static void main(String[] args) throws SQLException {
        //【测试数据库连接】
        System.out.println(DS.getConnection());//看是不是有值
    }
}

创建Image类:

@Getter
@Setter
@ToString
public class Image {
    private Integer imageId;
    private String imageName;
    private Long size;//图片大小
    private String uploadTime;//上传时间
    private String md5;//文件校验唯一性的md5校验码
    private String contentType;//图片的类型
    private String path;//图片保存的本地路径


}

创建 ImageDao 类:

public class ImageDAO {

    /**
     * 查询操作
     * @param md5
     * @return
     */
    public static int queryCount(String md5) {
//        try {
//           1.获取数据库链接 Connection
//           2.获取操作命令对象 Statement (connection + sql)
//           3.执行SQL:执行前替换占位符
//           4.如果是查询语句,需要处理结果集 ResultSet
//         }catch(..) {..}
//        finally {
//           5.释放资源
//         }
        Connection connection = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try{
           connection = Util.getConnection();
           String sql =
                   "select count(0) c from image_table where md5=? ";
           ps = connection.prepareStatement(sql);
           ps.setString(1,md5);
           rs = ps.executeQuery();
           rs.next();//指向下一行(rs初始指向的为null)
           return rs.getInt("c");

        }catch (SQLException e) {
            //变运行时异常
            throw new RuntimeException("查询上传图片MD5出错:"+md5,e);
        } finally {
            Util.close(connection,ps,rs);
        }
    }

    /**
     * 插入操作
     * @param image
     * @return
     */
    public static int insert(Image image) {
        Connection connection = null;
        PreparedStatement ps = null;
        try {
            connection = Util.getConnection();

            String sql = "insert into image_table values(null,?,?,?,?,?,?)";

            ps = connection.prepareStatement(sql);

            ps.setString(1,image.getImageName());
            ps.setLong(2,image.getSize());
            ps.setString(3,image.getUploadTime());
            ps.setString(4,image.getMd5());
            ps.setString(5,image.getContentType());
            ps.setString(6,image.getPath());

            return ps.executeUpdate();

        }catch (SQLException e){
            throw new RuntimeException("新增上传图片出错 ",e);
        } finally {
            Util.close(connection,ps);
        }
    }

    /**
     * 查询所有的图片--->展示
     * @return
     */
    public static List<Image> queryAll() {
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        try {
            connection = Util.getConnection();
            String sql = "select * from image_table";//一般不写*  要罗列出来呢
            statement = connection.prepareStatement(sql);
            resultSet = statement.executeQuery();

            List<Image> list = new ArrayList<>();
            while (resultSet.next()){
                Image image = new Image();
                image.setImageId(resultSet.getInt("image_id"));
                image.setImageName(resultSet.getString("image_name"));
                image.setContentType(resultSet.getString("content_type"));
                image.setMd5(resultSet.getString("md5"));
                list.add(image);
            }
            return list;
        } catch (SQLException e) {
            throw new RuntimeException("查询所有图片出错 ",e);
        } finally {
            Util.close(connection,statement,resultSet);
        }
    }
    /**
     * 展示指定图片
     * @param id
     * @return
     */
    public static Image queryOne(int id) {
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;

        try {
            connection = Util.getConnection();
            String sql = "select * from image_table where image_id=?";
            statement = connection.prepareStatement(sql);
            statement.setInt(1,id);
            resultSet = statement.executeQuery();

            Image image = null;
            while (resultSet.next()){
                image = new Image();
                image.setImageId(resultSet.getInt("image_id"));
                image.setImageName(resultSet.getString("image_name"));
                image.setContentType(resultSet.getString("content_type"));
                image.setMd5(resultSet.getString("md5"));
                image.setPath(resultSet.getString("path"));
            }
            return image;
        } catch (SQLException e) {
            throw new RuntimeException("查询所有图片出错 ",e);
        } finally {
            Util.close(connection,statement,resultSet);

        }
    }

    public static int delete(int id) {
        Connection connection = null;
        PreparedStatement statement = null;
        try {
          connection = Util.getConnection();
          connection.setAutoCommit(false);//不自动提交(开启事务)
          String sql = "delete from image_table where image_id=?";
          statement = connection.prepareStatement(sql);
          statement.setInt(1,id);
          int n = statement.executeUpdate();
          //TODO:删除本地图片文件
            connection.commit();
          return n;
        }catch (Exception e){//所有的异常  都要回滚,不止SQLException
            try {
                connection.rollback();
            } catch (SQLException se) {
                throw new RuntimeException("删除图片回滚出错:"+id,e);
            }
            throw new RuntimeException("删除图片出错:"+id,e);
        }finally {
            Util.close(connection,statement);
        }
    }
}