使用Servlet+Tomcat+jsp+mysql上传信息照片并给指定qq邮箱发送邮件将用户信息存于Mysql

JavaWeb四舍五入学完了,记录下这个小项目吧。
结合上传文件和邮件发送写了一个比较综合的小项目(强烈推荐狂神说Java,本来俺以为视频教学都相对比较浅的,喜欢看书,狂神真是个宝藏up主)。

整体逻辑

整个逻辑就是在网页上获取信息(可以有jpg格式的图片,其他文件不上传),由于在同一个上下文所以利用request将信息转发到获取类,将文件转成一个字节流(初衷是不想显式的保存在本地,直接上传,事实上流本来也是缓存在某个目录下的.tmp文件,所以如果想要保存也可以自行修改代码,调用代码中的savaImage方法),再发送一封邮件给指定邮箱,由于使用的qq邮箱作为发送者,所以配置为对应的smtp主机以及由于qq邮箱使用了SSL加密,所以也需要配置一下,并使用qq邮箱分配的验证码进行发送,如果有jpg格式的图片上传就一并发过去,没有就是固定的注册成功文字信息,然后再将用户信息(除文件外的信息),利用配置JDNI数据源,用它连接mysql数据库,然后将用户信息上传到数据库中。
————————————————————————————————

具体实现

建库

CREATE TABLE users(
id int PRIMARY KEY NOT NULL AUTO_INCREMENT,
username VARCHAR(20) NOT NULL,
`password` VARCHAR(20) NOT NULL,
email VARCHAR(20) NOT NULL
)ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=0;

实体类

public class User {
    private String userName;
    private String password;
    private String email;
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public void setEmail(String email) {
        this.email = email;
    }
    public String getPassword() {
        return password;
    }
    public String getEmail() {
        return email;
    }
}

DAO层

自定义的异常

public class DAOException extends Exception {
    private static final long serialVersionUID = 10102L;
    private String message;

    public DAOException(){}
    public DAOException(String message){
        this.message = message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    @Override
    public String toString() {
        return message;
    }
}

获取数据源,与Mysql数据库建立连接

public class DataSourceCache {
    private static DataSourceCache instance;
    private DataSource dataSource;
    static {
        instance = new DataSourceCache();
    }
    private DataSourceCache(){
        Context context = null;
        try {
            context = new InitialContext();
            //解析连接池
            context = (Context) context.lookup("java:comp/env");
            dataSource = (DataSource) context.lookup("jdbc/mysqll");
        } catch (NamingException e) {
            System.out.println("获取失败");
            e.printStackTrace();
        }
    }
    public static DataSourceCache getInstance(){
        return instance;
    }

    public DataSource getDataSource(){
        return dataSource;
    }
}

DAO接口,用于规范数据库的连接

public interface DAO {
    Connection getConection() throws DAOException;
}

DAO接口的基本实现类,连接Mysql数据库,获取连接和关闭资源

public class BaseDAO implements DAO {
    @Override
    public Connection getConection() throws DAOException {
        //获取连接池资源
        DataSource dataSource = DataSourceCache.getInstance().getDataSource();
        try{
            //如果成功获取返回连接资源
            return dataSource.getConnection();
        }catch (Exception e){
            e.printStackTrace();
            throw new DAOException();
        }
    }
    protected void closeDBObject(ResultSet resultSet, Statement statement, Connection connection){
        //关闭所有资源
        if(resultSet != null){
            try{
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if(statement != null){
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if(connection != null){
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

针对用户表的增和查(不过该项目中没用查功能)

public interface UserDAO extends DAO {
    List<User> getProducts()throws DAOException;
    void insert(User product) throws DAOException;
}

针对用户表的具体实现

public class UserDAOImpl extends BaseDAO implements UserDAO {
    private static final String GET_PRODUCTS_SQL = "SELECT username,password,email FROM users";
    private static final String INSERT_PRODUCT_SQL = "INSERT INTO users (username,password,email) VALUES(?,?,?)";
    @Override
    //查找
    public List<User> getProducts() throws DAOException {
        List<User> users = new ArrayList<>();
        Connection connection = null;
        PreparedStatement pStatement = null;
        ResultSet resultSet = null;
        try {
            connection = getConection();
            //预编译
            pStatement = connection.prepareStatement(GET_PRODUCTS_SQL);
            //执行
            resultSet = pStatement.executeQuery();
            while (resultSet.next()){
                User user = new User();
                user.setUserName(resultSet.getString("username"));
                user.setPassword(resultSet.getString("password"));
                user.setEmail(resultSet.getString("email"));
                users.add(user);
                System.out.println(user);
            }
        }catch (SQLException e){
            throw new DAOException("错误信息为:"+e.getMessage());
        }finally {
            closeDBObject(resultSet,pStatement,connection);
        }
        return users;
    }

    @Override
    //插入
    public void insert(User user) throws DAOException {
        Connection connection = null;
        PreparedStatement pStatement = null;
        try {
            connection = getConection();
            pStatement = connection.prepareStatement(INSERT_PRODUCT_SQL);
            pStatement.setString(1, user.getUserName());
            pStatement.setString(2, user.getPassword());
            pStatement.setString(3, user.getEmail());
            pStatement.execute();
        }catch (SQLException e){
            throw new DAOException("插入时出错 "+e.getMessage());
        }finally {
            closeDBObject(null,pStatement,connection);
        }

    }

}

获取具体用户类的工厂

package DAO;
public class DAOFactory {
    public static UserDAO getUserDAO(){
        return new UserDAOImpl();
    }
}

工具类

获取资源类,负责上传和获取信息

public class GetHead {
    private User user = new User();
    public User getUser() {
        return user;
    }
    private HttpServletRequest req;
    private String path;
    private InputStream inputStream;
    public GetHead(HttpServletRequest req,String path){
        this.req = req;
        this.path = path;
        getHead();
    }

    public InputStream getInputStream() {
        return inputStream;
    }

    private void getHead(){
        if(!ServletFileUpload.isMultipartContent(req)){
            //普通表单不处理
            return;
        }
        try {
            //创建对应文件夹
            String path = creatFolder("temp");
            DiskFileItemFactory factory = new DiskFileItemFactory();
            //设置临时存放目录,防止存入默认系统盘
            factory.setRepository(new File(path));
            //设置内存缓存区,超过则写入临时文件
            factory.setSizeThreshold(4096);
            ServletFileUpload upload = new ServletFileUpload(factory);
            //设置编码格式,防止中文乱码
            upload.setHeaderEncoding("utf-8");
            List<FileItem> fileItems = upload.parseRequest(req);
            for (FileItem fileItem : fileItems) {
                String uploadFileName = fileItem.getName();
                if(uploadFileName==null){
                    String fled = fileItem.getFieldName();
                    String value = fileItem.getString("utf-8");
                    selectSet(fled,value);
                }
                if(uploadFileName==null||uploadFileName.trim().equals("")||!uploadFileName.substring(uploadFileName.lastIndexOf(".")+1).equals("jpg")){
                    continue;
                }
                inputStream = fileItem.getInputStream();
                //saveImage(inputStream);
                //删除临时文件
                fileItem.delete();
                break;
            }
        } catch (FileUploadException | UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void selectSet(String fled,String value){
        if(fled.equals("username")){
            req.setAttribute("username",value);
            user.setUserName(value);
        }else if("password".equals(fled)){
            user.setPassword(value);
        }else if("email".equals(fled)){
            user.setEmail(value);
        }
    }

    private String creatFolder(String path_1){
        String path = this.path+"/"+path_1;
        File file = new File(path);
        if(!file.exists()){
            file.mkdir();
        }
        return path;
    }

    private void saveImage(InputStream inputStream) throws IOException {
        //如想保存下上传图片可以在上面调用该类
        FileOutputStream fos = new FileOutputStream(path+"image.jpg");
        byte[] buffer = new byte[1024*1024];
        int len =0;
        while((len=inputStream.read(buffer))>0){
            fos.write(buffer,0,len);
        }
        fos.close();
        inputStream.close();
    }

}

发送邮件类,由于发送邮件需要一定的耗时,考虑用户体验继承了Thread,开一个子线程专门负责发送

public class SendEmail extends Thread {
    private User user;
    private InputStream inputStream;
    public SendEmail(InputStream inputStream,User user){
        this.inputStream = inputStream;
        this.user = user;
    }

    public SendEmail(User user){
        this.user = user;
    }


    @SneakyThrows
    @Override
    public void run()  {
        //创建一个配置文件
        Properties prop = new Properties();
        //定位到qq邮件服务器
        prop.setProperty("mail.host","smtp.qq.com");
        //设置邮件发送协议
        prop.setProperty("mail.transport.protocol","smtp");
        // 需要验证用户名密码
        prop.setProperty("mail.smtp.auth","true");
        //因为QQ有一个SSL加密所以也需要设置一下,如果是其他邮箱就不要这一步
        MailSSLSocketFactory sf = new MailSSLSocketFactory();
        sf.setTrustAllHosts(true);
        prop.put("mail.smtp.ssl.enable","true");
        prop.put("mail.smtp.socketFactory",sf);
        //创建session保证在整个会话中有效
        Session session = Session.getDefaultInstance(prop, new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication("邮箱地址","授权码");
            }
        });
        //开启debug模式,打印运行状态
        session.setDebug(true);
        //得到连接对象,并通过用户账号与授权码连接上服务器
        Transport ts = session.getTransport();
        ts.connect("smtp.qq.com","邮箱地址","授权码");
        //创建邮件

        MimeMessage message = new MimeMessage(session);
        //设置主题
        message.setSubject("你好!"+user.getUserName());
        //设置发送人
        message.setFrom(new InternetAddress("邮箱地址"));
        //TO表示主要接收人,CC表示抄送人,BCC表示秘密抄送人、
        //设置收件人
        message.setRecipient(Message.RecipientType.TO,
                new InternetAddress(user.getEmail()));
        //附件(这里是照片)
        MimeBodyPart image=null;
        //如需要本地图片的方式就用以下代码。而不用ByteArrayDataSource类
        //FileDataSource file = new FileDataSource("E:\\javaWeb\\javaweb-01-maven02\\mail-teat\\
        // target\\mail-teat\\WEB-INF\\update\\image.jpg");
        if(inputStream!=null) {
            //第二个参数为MIME类型,可自行百度
            DataSource source = new ByteArrayDataSource(inputStream, "image/jpeg");
            image = new MimeBodyPart();
            DataHandler dh = new DataHandler(source);
            image.setDataHandler(dh);
            image.setContentID("image.jpg");
        }
        MimeBodyPart text = new MimeBodyPart();
        text.setContent("<h1>恭喜您!<h1> <p style=\"color: pink\">"+user.getUserName()+
                //如果不在此处加以标注为img,就会作为附件为bin的格式发送
                "</p><br/><img src='cid:image.jpg'>" +
                "<br/> 注册成功,您的密码为"
                +user.getPassword()+"请妥善保管","text/html;charset=UTF-8");

        MimeMultipart mm = new MimeMultipart();
        mm.addBodyPart(text);
        if(inputStream!=null) {
            mm.addBodyPart(image);
        }
        //选择封装方式,有三种
        mm.setSubType("related");
        message.setContent(mm);
        message.saveChanges();
        ts.sendMessage(message,message.getAllRecipients());
        ts.close();
        if(inputStream!=null) {
            inputStream.close();
        }
    }
    public void setUser(User user) {
        this.user = user;
    }
}

控制器类

@WebServlet(urlPatterns = {"/RegisterServlet.do"})
public class RegisterServlet extends javax.servlet.http.HttpServlet {
    @Override
    protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
        //将request交给getHead工具类处理获取信息
        GetHead getHead = new  GetHead(request,getServletContext().getRealPath("/WEB-INF"));
        User user = getHead.getUser();
        SendEmail sendEmail = new SendEmail(getHead.getInputStream(),user);
        //为了用户体验所以这里开了一个线程

        sendEmail.start();
        //将用户存入数据库
        SaveUserAction.save(user);
        //转发到成功页面
        request.getRequestDispatcher("WEB-INF/Sucese.jsp").forward(request,response);
    }

    @Override
    protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {

    }
}

jsp页面

注册页面

<%@page contentType="text/html;charset=utf-8" language="java" %>
<%@ page isELIgnored="false"%>
<html>
<head>
    <title>发送邮件</title>
</head>
<body>
    <form action="${pageContext.request.contextPath}/RegisterServlet.do" method="post" enctype="multipart/form-data">
        用户名:<input type="text" name="username"><br/>
        密码:<input type="password" name="password"><br/>
        邮箱:<input type="text" name="email"><br/>
        头像(仅限jpg格式):<input type="file" name="head"><br/>
        <input type="submit" value="注册">
    </form>

</body>
</html>

反馈页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false"%>
<html>
<head>
    <title>注册信息</title>
</head>
<body>
    ${username},注册邮件已发送到指定邮箱,请注意查收
</body>
</html>

总结

这个项目倒是没有什么难点,坑倒是意外的不少,上一篇文章的连接数据源那些疯狂写错的蠢蠢的坑
然后是今天想着反之传输的也是二进制文件 (可以尝试将发送邮件中关于是图片的那行html代码注释掉,然后用本地文件的方式发送,就会发现邮箱无法识别该文件,默认识别为.bin(二进制文件)) 想着为啥不能直接发送,干嘛要本地存一遍,不过通过看Debug看inputStream的信息发现,字节流也是将这些缓存成一个tmp文件,不过俺还是不想显式的存下来所以就参考了许多博文,最后发现了代码中的方法,这个问题算是解决了,
最后又遇到了无法获取到DAO层中自写的类的问题,本地不报错,服务器上报错,那问题就可以定位到部署的文件夹下对有对应的.class文件,发现该文件夹下没有的DAO层对应的文件夹没有根据我的修改包名同步修改,rebuild了也没用,手动改后,问题解决。
github垃圾代码贡献者就是我了,不过需要自己改下配置啥的

发布了18 篇原创文章 · 获赞 1 · 访问量 260

猜你喜欢

转载自blog.csdn.net/qq_38732834/article/details/105444861