云图—个个人的云相册

353 阅读5分钟

项目截图

image.png

image.png

其中素材,以及一些关键代码的实现参考链接:一个云上相册

项目实现

简介

云图是一个基于springboot框架的个人云相册,能够实现简单的本地相片存储,最终用户存储的照片会存储于腾讯云存储桶。上传细节的实现请参照实现照片上传到腾讯云存储桶

本文博主重点描述一下在项目过程技术实现。

qq邮件功能

本项目实现了用qq邮件的形式实现账号的激活。

数据库部分用户表的设计:

image.png

STATUS代表账号激活情况,用户在注册成功后会受到一封qq邮件,点击qq邮件进行激活账号,STATUS中存储的信息也就由N->Y,代表账户激活成功(当然此处也可以用接收验证码实现,大体逻辑相同)。

一些实体类的实现博主在此便不再赘述,源码已放于文末

实现流程:

引入依赖

 <!-- 文件上传使用的第三方库 -->
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.3.1</version>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.8.0</version>
        </dependency>

MailUtils类

public final class MailUtils {
    //20b30176d4526d69
    private static final String USER = "2507062649@qq.com"; // 发件人称号,同邮箱地址
    private static final String PASSWORD = ""; // 如果是qq邮箱可以使用授权码,或者登录密码,授权码获取方式下文已经给出

    /**
     * @param to    收件人邮箱
     * @param text  邮件正文
     * @param title 标题
     */
    /* 发送验证信息的邮件 */
    public static boolean sendMail(String to, String text, String title) {
        try {
            final Properties props = new Properties();
            props.put("mail.smtp.auth", "true");
            props.put("mail.smtp.host", "smtp.qq.com");

            // 发件人的账号
            props.put("mail.user", USER);
            //发件人的密码
            props.put("mail.password", PASSWORD);

            // 构建授权信息,用于进行SMTP进行身份验证
            Authenticator authenticator = new Authenticator() {
                @Override
                protected PasswordAuthentication getPasswordAuthentication() {
                    // 用户名、密码
                    String userName = props.getProperty("mail.user");
                    String password = props.getProperty("mail.password");
                    return new PasswordAuthentication(userName, password);
                }
            };
            // 使用环境属性和授权信息,创建邮件会话
            Session mailSession = Session.getInstance(props, authenticator);
            // 创建邮件消息
            MimeMessage message = new MimeMessage(mailSession);
            // 设置发件人
            String username = props.getProperty("mail.user");
            InternetAddress form = new InternetAddress(username);
            message.setFrom(form);

            // 设置收件人
            InternetAddress toAddress = new InternetAddress(to);
            message.setRecipient(Message.RecipientType.TO, toAddress);

            // 设置邮件标题
            message.setSubject(title);

            // 设置邮件的内容体
            message.setContent(text, "text/html;charset=UTF-8");
            // 发送邮件
            Transport.send(message);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    public static void main(String[] args) throws Exception { // 做测试用
        MailUtils.sendMail("@qq.com", "阿狗在吗,晚上早点睡晚安。勿念勿回复。", "测试邮件");
        System.out.println("发送成功");
    }


}

qq邮箱授权码获取

图片上传部分代码实现

前端部分

home.html

<form id="fileForm" action="/image/upload" onsubmit="return checkFileSize()" method="post"
                  enctype="multipart/form-data" class="navbar-form navbar-left">
                <div class="form-group" style="border-color: #3c3c3c">
                    <input id="files" class="form-control" type="file" name="upload" multiple required>
                    <input type="submit" class="btn btn-success" value="上传"/>
                </div>
</form>

后端部分

 @PostMapping("/upload")
    public void upload(HttpServletRequest req, HttpServletResponse resp) throws Exception {

        
        //1.做准备工作,获得upload对象,该对象可以解析请求
        FileItemFactory factory = new DiskFileItemFactory();
        ServletFileUpload upload = new ServletFileUpload(factory);
        List<FileItem> items;

        try {
            //1.1解析请求,获得文件项列表,关键代码实现
            items = upload.parseRequest(req);
        } catch (FileUploadException e) {
            e.printStackTrace();
            //解析请求对象失败
            resp.sendRedirect("/user/error");

            return;
        }

        //先遍历一遍文件项确保没有非图片类型的文件
        for (FileItem item : items) {
            if (!item.getContentType().contains("image")) {
                //说明用户上传的不是图片,需要告诉用户
                resp.sendRedirect("/user/error");
                return;
            }
        }

        //获取session中的登录信息
        User user = (User) (req.getSession().getAttribute("user"));
        //开始处理文件
        for (FileItem item : items) {
            //2.封装Image对象
            Image image = new Image();

            image.setUid(user.getId());

            //2.1格式化上传时间
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
            image.setUploadTime(format.format(new Date()));

          

            //2.2获取文件的名字
            image.setImageName(parseFileName(item.getName()));
            image.setContentType(item.getContentType());

            //2.3利用md5,用图片的二进制数据进行求MD5加密码,将来存储一样的图片时可以节省磁盘空间
            image.setMd5(DigestUtils.md2Hex(item.get()));



            //2.4设置路径,用MD5可以防止覆盖图片

            //3.先写入磁盘(在写入前会查询数据库是否有数据,无则说明第一次存储图片,可以写入腾讯云存储桶)

            //3.1获取项目的部署路径
     
            /*File file = new File(image.getPath());*/


            try {
                //再写入磁盘之前我们先查询一下数据库中是否有了该图片
                Image imageByMD5 = imageService.findImageByMD5(image.getMd5(), user.getId());
               
                if (imageByMD5 == null) {
                    //数据库中没有该图片,说明是第一次存储,这时候我们才写入云存储桶

                   /* item.write(file);*/此处实现的是一个写入本地磁盘的接口,可以根据需要自行选择
                    //将FIleItem对象转为File对象
                    File toFile = new File(image.getImageName());

                    item.write(toFile);

                    //上传到腾讯云存储桶
                    String fileName = TencentCOS.uploadfile(toFile);//参见上文简介中链接

                    image.setPath(fileName);//此处的fileName即为云存储桶中的路径了
                    image.setSize((int) item.getSize());
                }
                //4.不管磁盘写不写入,数据库中的记录都要写进去
                imageService.insertImage(image);
            } catch (Exception e) {
                e.printStackTrace();
                //写入磁盘出错
                resp.sendRedirect("/user/error");
                return;
                
            }
        }
        //因为是多文件,所以当所有文件都处理完毕后再重定向
        //这里我们可以重定向刷新页面
        resp.sendRedirect(req.getContextPath() + "/user/home");
    }

其中代码中一些MD5加密作者在此就不再赘述

关于代码中的TencentCOS.upload()函数就是实现就在博主在简介链接中。

图片显示部分代码实现

前端部分

<div v-for="image in images" style="border-radius: 15%">
                <img id="sImage" style="border-radius: 10%;width: 200px;height: 200px;"
                     v-bind:src="'/image/show?imageId='+image.imageId" v-on:click="showBigImage(image.imageId)"
                     alt="图片正在拼命加载">
                <font style="font-family: SimSun;font-size: 12px">{{image.imageName}}</font><br/>
                <font style="font-family: SimSun;font-size: 12px">上传时间:{{image.uploadTime}}</font><br/>
                <button style="border-radius: 100%;background-color: aquamarine;float: left"
                        v-on:click.stop="deleteImage(image.imageId)"></button>
                <button style="border-radius: 100%;background-color: aquamarine;float: right;" v-on:click.stop="downloadImage(image.imageId)"></button>
</div>

后端部分

@GetMapping("/show")
    public void show(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {


        ResultInfo info = new ResultInfo();
        //先获取当前的用户id
        User user = (User) (req.getSession().getAttribute("user"));
        //1.获取请求参数的imageId,根据该参数查询图片
        String imageId = req.getParameter("imageId");

        if (imageId == null || "".equals(imageId)) {
            //没有改imageId的值就无法访问
            info.setFlag(false);
            info.setErrorMsg("因神秘力量干扰,无法访问");
            writeValue(info, resp);
            return;
        }

        Image image = imageService.findByImageId(Integer.parseInt(imageId), user.getId());
        //输出字节流到浏览器
        //File file = new File(image.getPath());

        byte[] buffer = new byte[1024 * 20];
        //1.创建输入流,用于写入缓冲区
       /* BufferedInputStream in = new BufferedInputStream(new FileInputStream(file));*///从本地文件中获取输入流写到缓存区
        BufferedInputStream in = new BufferedInputStream(TencentCOS.showFile(image.getPath()));
        //2.创建输出流,用于输出数据
        //2.1这里记得设置类型,否则会显示失败
        resp.setContentType(image.getContentType());
        BufferedOutputStream out = new BufferedOutputStream(resp.getOutputStream());
        while (true) {
            int len = in.read(buffer);
            if (len == -1) {
                //数据读取完毕
                break;
            } else {
                out.write(buffer);//将字节流写到网页中,img标签便会显示图片
            }
        }
        //记得关闭
        in.close();
        out.close();
    }

至于删除图片以及下载图片到本地的功能博主在这里就不再详述了,有兴趣的小伙伴可以下载本程序的源码,由于博主也是参考别人的代码实现,所以小伙伴们引用时请注明出处。(文末附源码下载地址)

程序源码

源码链接gitee仓库