文件上传、MD5加密与验证码的功能实现

news2024/11/26 0:11:58

UUID工具类

1.概述:UUID 是通用唯一识别码(Universally Unique Identifier)的缩写。UUID 让分布式系统中的所有元素,都能有唯一的辨识信息,而不需要通过中央控制端来做辨识信息的指定。

是一个软件建构的标准,也是被开源软件基金会 (Open Software Foundation, OSF) 的组织在分布式计算环境 (Distributed Computing Environment, DCE) 领域的一部份。

UUID 的目的,是让分布式系统中的所有元素,都能有唯一的辨识资讯,而不需要透过中央控制端来做辨识资讯的指定。如此一来,每个人都可以建立不与其它人冲突的 UUID。在这样的情况下,就不需考虑数据库建立时的名称重复问题。目前最广泛应用的 UUID,即是微软的 Microsoft's Globally Unique Identifiers (GUIDs),而其他重要的应用,则有 Linux ext2/ext3 档案系统、LUKS 加密分割区、GNOME、KDE、Mac OS X 等等。

2.UUID 的组成

  • 1~8位采用系统时间,在系统时间上精确到毫秒级保证时间上的惟一性;
  • 9~16位采用底层的IP地址,在服务器集群中的惟一性;
  • 17~24位采用当前对象的HashCode值,在一个内部对象上的惟一性;
  • 25~32位采用调用方法的一个随机数,在一个对象内的毫秒级的惟一性。
     

Java生成UUID的例子:

import java.util.UUID;
 
public class UUIDGenerator {
    public UUIDGenerator() {
    }
 
    public static String getUUID() {
        UUID uuid = UUID.randomUUID();
        String str = uuid.toString();
        // 去掉"-"符号
        String temp = str.substring(0, 8) + str.substring(9, 13) + str.substring(14, 18) + str.substring(19, 23) + str.substring(24);
        return str + "," + temp;
    }
 
    //获得指定数量的UUID
    public static String[] getUUID(int number) {
        if (number < 1) {
            return null;
        }
        String[] ss = new String[number];
        for (int i = 0; i < number; i++) {
            ss[i] = getUUID();
        }
        return ss;
    }
 
    public static void main(String[] args) {
        String[] ss = getUUID(10);
        for (int i = 0; i < ss.length; i++) {
            System.out.println("ss[" + i + "]=====" + ss[i]);
        }
    }
}

控制台运行效果 

文件上传 

 编程思路:

  • 本地文件输入到网络上
  • 网络再把文件输出到服务器上]
  • 服务器读取文件
  • 服务器把文件写入到指定位置

MultipartFile接口常用的的API见下表:

方法功能描述
String getOriginalFilename() 获取上传文件的原始文件名,即该文件在客户端中的文件名
boolean isEmpty()判断上传的文件是否为空,当没有选择文件就直接上传,或者选中的文件是0字节的空文件时,返回true,否则返回false
long getSize()获取上传的文件大小,以字节为单位
String getContentType()根据所上传的文件的扩展名决定该文件的MIME类型,例如上传.jpg格式的图片,将返回image/jpeg
InputStream getInputStream()获取上传文件的输入字节流,通常用于自定义读取所上传的文件的过程,该方法与transferTo()方法不可以同时使用
void transferTo(File dest) 保存上传的文件,该方法与getInputStream()方法不可以同时使用
@WebServlet("/upload")
@MultipartConfig(maxFileSize = 4*1024*1024)
public class FileUploadbank extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("utf-8");
        response.setCharacterEncoding("utf-8");

        String uname = request.getParameter("uname");
        System.out.println(uname);

        Part pic = request.getPart("pic");
        String contentType = pic.getContentType();
        String submittedFileName = pic.getSubmittedFileName();
        String name = pic.getName();
        long size = pic.getSize();

        System.out.println("contentType:"+contentType);
        System.out.println("submittedFileName:"+submittedFileName);
        System.out.println("name:"+name);
        System.out.println("size:"+size);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}

 

@WebServlet("/upload")
@MultipartConfig(maxFileSize = 4*1024*1024)
public class FileUpload extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置请求和响应的编码格式
        request.setCharacterEncoding("utf-8");
        response.setCharacterEncoding("utf-8");

        Part pic = request.getPart("pic");
        String submittedFileName = pic.getSubmittedFileName();
        //获得一个永远不会重复的文件名字
        submittedFileName = UUID.randomUUID().toString().replace("-","").toUpperCase()+new Date().getTime() +submittedFileName;
        //获得服务器根目录下面upload文件夹的路径
        String realPath = request.getSession().getServletContext().getRealPath("/upload");
        //写入服务器指定文件夹,存储某个文件名字
        pic.write(realPath+"/"+submittedFileName);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}

注意:form表单的请求方式必须设置为POST,并配置属性enctype=“multipart/form-data”,文件上传input控件的name属性值需设置为file值。 

项目架构

MySQL创建数据库和表;

#创建表
create table t_user(
uid int(11) primary key not null auto_increment,
uname varchar(20),
pwd varchar(32),
realname varchar(20),
sex varchar(11),
address varchar(50),
userImg varchar(100),
salt varchar(32)
)

 创建项目并变为web项目,导入jar包;

项目中用户头像的上传

编程思路:

1、设置register.jsp页面:文件传输需要设置表单的enctype 为 multipart/form-data;略缩图

register.jsp页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>注册页</title>
    <style>
        #imgPreview img {
            width: 80px;
            height: 80px;
            margin: 10px 5px;
        }
    </style>
    <script src="js/jquery.min.js"></script>
    <script>
        $(function () {
            $("#fileupload").change(function () {
                if (typeof (FileReader) != "undefined") {
                    //先把略缩图div内容清空
                    var dvPreview = $("#imgPreview");
                    dvPreview.html("");
                    //拿到文件对象
                    var file = $($(this)[0].files[0]); //获取输入框的文件对象
                    var reader = new FileReader(); //定义文件缓存读取对象
                    reader.readAsDataURL(file[0]); //读取缓存中的文件对象
                    reader.onload = function (e) {
                        var img = $("<img />");
                        img.attr("src", e.target.result);
                        dvPreview.append(img);
                    }
                }else {
                    alert("This browser does not support HTML5 FileReader.");
                }
            });
        });
    </script>
</head>
<body>
<h2>欢迎注册</h2>
<!--文件传输需要设置表单的enctype 为 multipart/form-data-->
<form action="register" method="post" enctype="multipart/form-data">
    昵称:<input type="text" name="uname" value=""> <br>
    密码:<input type="password" name="pwd" value=""> <br>
    姓名:<input type="text" name="realname" value=""> <br>
    性别:<input type="radio" name="sex" value="男">男 <input type="radio" name="sex" value="女">女 <br>
    地址:<input type="text" name="address" value=""> <br>
    头像:<input type="file" name="upload" value="" id="fileupload"> <br>
    <div id="imgPreview"></div>
    <input type="submit" value="提交"><a href="index.jsp">有帐号? 点击登录</a><br>
</form>
</body>
</html>

页面效果如下: 

 

"enctype='multipart/form-data'" 指示使用 "multipart/form-data" 编码类型提交表单数据。这种编码类型允许在表单中包含文件上传字段。

  • enctype就是encodetype就是编码类型的意思。
  • multipart/form-data是指表单数据有多部分构成,既有文本数据,又有文件等二进制数据的意思。

注意:默认情况下,enctype的值是application/x-www-form-urlencoded,不能用于文件上传,只有使用了multipart/form-data,才能完整的传递文件数据。

  • application/x-www-form-urlencoded不是不能上传文件,是只能上传文本格式的文件。
  • multipart/form-data是将文件以二进制的形式上传,这样可以实现多种类型的文件上传。

2、 获得头像路径并存入user对象

@MultipartConfig标注属性
fileSizeThersholdint型  是(可选)当前数据量大于该值时,内容将被写入文件
locationString型是(可选)存放生成文件的地址
maxFileSizelong型是(可选)允许上传的文件最大值,默认为-1,表示没有限制
maxRequestSizelong型是(可选)针对 multipart/form-data 请求的最大数量

 UserRegister.java

@WebServlet("/register")
@MultipartConfig(maxFileSize = 4*1024*1024)
public class UserRegister extends HttpServlet {

    UserService userService = new UserServiceImpl();

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("utf-8");
        response.setCharacterEncoding("utf-8");
        //1.获取页而提交的赏规教花
        User user = new User();
        user.setUname(request.getParameter("uname"));
        user.setPwd(request.getParameter( "pwd"));
        user.setRealname(request.getParameter( "realname"));
        user.setSex(request.getParameter("sex"));
        user.setAddress(request.getParameter( "address"));

        /**
         * 2.完成图片上传
         */

        //2.1拿到头像图片对象
        Part upload = request.getPart("upload");
        //2.2获取用户上传的图片的原始名字
        String fileName = upload.getSubmittedFileName();
        //2.3把原始名更改为一个永远会重复的文件名字:UUID+时间戳+原始名字
        fileName= UUID.randomUUID().toString().replace( "-", "").toUpperCase() + new Date().getTime() +fileName;
        //2.4获得头像在服务器存储的路径--获得头像图片在服务器存储的路径
        String path = request.getSession().getServletContext().getRealPath( "/upload");
        //2.5判断文件不存在则创建文件
        File file = new File(path);
        if(!file.exists()){
            file.mkdirs();
        }
        //2.6把图片文件写人到 指定路径 指定名字 存储起来
        upload.write( path+"/"+fileName);
        //3.补充用户头像图片的完整路径,存入User对象
        user.setUserImg("upload/"+fileName);

        //执行数据库的插入,把user对象的值插入数据库中
        boolean flag = userService.insert(user);
        if(flag){
            response.sendRedirect("index.jsp");
        }
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}

使用MD5进行密码加密

MD5加密

  • MD5算法为计算机安全领域广泛使用的一种散列函数,用于提供消息的完整性,是计算机广泛使用的哈希算法之一
  • MD5的固定长度为128比特,16字节,通常用他的16进制字面值输出他,是一个长度为32位的字符串。

MD5特点

  • 长度固定(无论输入多少字节,输出总是16字节)
  • 不可逆(从结果无法反推原始数据)
  • 具有高度的离散性(输出的16字节数据,没有任何规律可言,无法预测结果)
  • 抗碰撞性(在原始数据固定的情况下,几乎不会出现两个数据的MD5相同)

MD5应用场景

  • 用户密码保护:在保存用户密码时,不记录密码本身,只记录密码的MD5结果(即使数据库被盗也无法反推出明文)
  • 文件完整性校验:先在发送端计算一次文件的MD5,并把结果发送给接收端,接收端在接受文件后也计算一次MD5,两次结果一致文件完整。
  • 云盘秒传:云盘上传时计算MD5,并在自己的数据库中搜索一下 MD5是否存在,存在则使用已有的文件就可以了,从而实现云盘秒传。
  • 数字签名:发布程序时同时发布其MD5,下载后比较MD5是否相同,就可知道程序是否被篡改。
     

代码展示 

public class Test01 {
    public static void main(String[] args) {
        //创建加密类对象,使用MD5加密规则
        Digester md5 = new Digester(DigestAlgorithm.MD5);
        String pwd = md5.digestHex("123");
        System.out.println(pwd);
    }
}

控制台输出 

MD5加盐加密 

实现方式 

package com.zhan.util;

import java.security.MessageDigest;
import java.util.Random;

public class MD5Utils {

    /**
     * byte[]字节数组 转换成 十六进制字符串
     *
     * @param arr 要转换的byte[]字节数组
     *
     * @return  String 返回十六进制字符串
     */
    private static String hex(byte[] arr) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < arr.length; ++i) {
            sb.append(Integer.toHexString((arr[i] & 0xFF) | 0x100).substring(1, 3));
        }
        return sb.toString();
    }




    /**
     * MD5加密,并把结果由字节数组转换成十六进制字符串
     *
     * @param str 要加密的内容
     *
     * @return String 返回加密后的十六进制字符串
     */
    private static String md5Hex(String str) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] digest = md.digest(str.getBytes());
            return hex(digest);
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println(e.toString());
            return "";
        }
    }



    /**
     * 生成含有随机盐的密码
     *
     * @param password 要加密的密码
     *
     * @return String 含有随机盐的密码
     */
    public static String getSaltMD5(String password) {
        // 生成一个16位的随机数
        Random random = new Random();
        StringBuilder sBuilder = new StringBuilder(16);
        sBuilder.append(random.nextInt(99999999)).append(random.nextInt(99999999));
        int len = sBuilder.length();
        if (len < 16) {
            for (int i = 0; i < 16 - len; i++) {
                sBuilder.append("0");
            }
        }
        // 生成最终的加密盐
        String salt = sBuilder.toString();
        password = md5Hex(password + salt);
        char[] cs = new char[48];
        for (int i = 0; i < 48; i += 3) {
            cs[i] = password.charAt(i / 3 * 2);
            char c = salt.charAt(i / 3);
            cs[i + 1] = c;
            cs[i + 2] = password.charAt(i / 3 * 2 + 1);
        }
        return String.valueOf(cs);
    }



    /**
     * 验证加盐后是否和原密码一致
     *
     * @param password 原密码
     *
     * @param password 加密之后的密码
     *
     *@return boolean true表示和原密码一致   false表示和原密码不一致
     */
    public static boolean getSaltverifyMD5(String password, String md5str) {
        char[] cs1 = new char[32];
        char[] cs2 = new char[16];
        for (int i = 0; i < 48; i += 3) {
            cs1[i / 3 * 2] = md5str.charAt(i);
            cs1[i / 3 * 2 + 1] = md5str.charAt(i + 2);
            cs2[i / 3] = md5str.charAt(i + 1);
        }
        String Salt = new String(cs2);
        return md5Hex(password + Salt).equals(String.valueOf(cs1));
    }



    public static void main(String[] args) {
        // 原密码
        String plaintext = "123456";

        // 获取加盐后的MD5值
        String ciphertext = MD5Utils.getSaltMD5(plaintext);
        System.out.println("加盐后MD5:" + ciphertext);
        System.out.println("是否是同一字符串:" + MD5Utils.getSaltverifyMD5(plaintext, ciphertext));
    }
}

 控制台输出

 

 MD5和SHA-1混合加盐加密 

 实现方式

package com.zhan.util;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Random;

public class MD5Utils {

    /**
     * md5和sha-1混合加密
     *
     * @param inputText 要加密的内容
     *
     * @return String md5和sha-1混合加密之后的密码
     */
    public static String md5AndSha(String inputText) {
        return sha(md5(inputText));
    }


    /**
     * md5加密
     *
     * @param inputText 要加密的内容
     *
     * @return String  md5加密之后的密码
     */
    public static String md5(String inputText) {
        return encrypt(inputText, "md5");
    }


    /**
     * sha-1加密
     *
     * @param inputText  要加密的内容
     *
     * @return  sha-1加密之后的密码
     */
    public static String sha(String inputText) {
        return encrypt(inputText, "sha-1");
    }


    /**
     * md5或者sha-1加密
     *
     * @param inputText   要加密的内容
     *
     * @param algorithmName  加密算法名称:md5或者sha-1,不区分大小写
     *
     * @return String  md5或者sha-1加密之后的结果
     */
    private static String encrypt(String inputText, String algorithmName) {
        if (inputText == null || "".equals(inputText.trim())) {
            throw new IllegalArgumentException("请输入要加密的内容");
        }
        if (algorithmName == null || "".equals(algorithmName.trim())) {
            algorithmName = "md5";
        }
        String encryptText = null;
        try {
            MessageDigest m = MessageDigest.getInstance(algorithmName);
            m.update(inputText.getBytes("UTF8"));
            byte s[] = m.digest();
            return hex(s);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return encryptText;
    }



    /**
     * byte[]字节数组 转换成 十六进制字符串
     *
     * @param arr 要转换的byte[]字节数组
     *
     * @return  String 返回十六进制字符串
     */
    private static String hex(byte[] arr) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < arr.length; ++i) {
            sb.append(Integer.toHexString((arr[i] & 0xFF) | 0x100).substring(1, 3));
        }
        return sb.toString();
    }



    /**
     * 生成含有随机盐的密码
     *
     * @param password 要加密的密码
     *
     * @return String 含有随机盐的密码
     */
    public static String getSaltMd5AndSha(String password) {
        // 生成一个16位的随机数
        Random random = new Random();
        StringBuilder sBuilder = new StringBuilder(16);
        sBuilder.append(random.nextInt(99999999)).append(random.nextInt(99999999));
        int len = sBuilder.length();
        if (len < 16) {
            for (int i = 0; i < 16 - len; i++) {
                sBuilder.append("0");
            }
        }
        // 生成最终的加密盐
        String salt = sBuilder.toString();
        password = md5AndSha(password + salt);

        char[] cs = new char[48];
        for (int i = 0; i < 48; i += 3) {
            cs[i] = password.charAt(i / 3 * 2);
            char c = salt.charAt(i / 3);
            cs[i + 1] = c;
            cs[i + 2] = password.charAt(i / 3 * 2 + 1);
        }
        return String.valueOf(cs);
    }



    /**
     * 验证加盐后是否和原密码一致
     *
     * @param password 原密码
     *
     * @param password 加密之后的密码
     *
     *@return boolean true表示和原密码一致   false表示和原密码不一致
     */
    public static boolean getSaltverifyMd5AndSha(String password, String md5str) {
        char[] cs1 = new char[32];
        char[] cs2 = new char[16];
        for (int i = 0; i < 48; i += 3) {
            cs1[i / 3 * 2] = md5str.charAt(i);
            cs1[i / 3 * 2 + 1] = md5str.charAt(i + 2);
            cs2[i / 3] = md5str.charAt(i + 1);
        }
        String salt = new String(cs2);
        String encrypPassword = md5AndSha(password + salt);

        // 加密密码去掉最后8位数
        encrypPassword = encrypPassword.substring(0 , encrypPassword.length() - 8);

        return encrypPassword.equals(String.valueOf(cs1));
    }



    public static void main(String[] args) {
        // 原密码
        String plaintext = "123456";

        // 获取加盐后的MD5值
        String ciphertext = MD5Utils.getSaltMd5AndSha(plaintext);
        System.out.println("加盐后MD5:" + ciphertext);
        System.out.println("是否是同一字符串:" + MD5Utils.getSaltverifyMd5AndSha(plaintext, ciphertext));
    }

}

控制台输出

 

项目创建工具类

Druid(德鲁伊)
Druid连接池是阿里巴巴开源的数据库连接池项目
功能强大,性能优秀,是Java语言最好的数据库连接池之一
3.Driud使用步骤

  • 导入jar包druid-1.1.12.jar
  • 定义配置文件.properties
  • 加载配置文件
  • 获取数据库连接池对象
  • 获取连接

 jdbc.properties

 

JDBCUtil.java

/**
 *数据库连接工具类
 */

public class JDBCUtil {
    //定义数据源
    private static DataSource dataSource;

    /**
     * 静态代码块:编译后自动执行
     * 加载配置文件,获得数据库的数据源
     */
    static {
        //在src根日英下陵最jdbc的配置文件,获想一个输入减
        InputStream inputStream = JDBCUtil.class.getClassLoader().getResourceAsStream("jdbc.properties");
        try {
            //创建Properties对象,加载输入流
            Properties properties = new Properties();
            properties.load(inputStream);
            //使用Druid连接池技术管理数据库的数据源
            dataSource = DruidDataSourceFactory.createDataSource(properties);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 通过阿里巴巴的德鲁伊连接池获得数据库连接
     * @return
     */

    public static Connection getConnection() {
        try {
            return dataSource.getConnection();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 资源的释放
     * @param rs
     * @param ps
     * @param conn
     */

    public static void close(ResultSet rs, PreparedStatement ps,Connection conn){
        try {
            DbUtils.close(rs);
            DbUtils.close(ps);
            DbUtils.close(conn);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

dao层 

 

 实现类

public class UserDaoImpl implements UserDao {
    private QueryRunner queryRunner = new QueryRunner();
    private Connection conn = JDBCUtil.getConnection();
    private String sql = null;

    @Override
    public List<User> selectAll() throws SQLException {
        sql ="select * from t_user";
        //指定结果集要封装到哪个实体类
        BeanListHandler<User> beanListHandler = new BeanListHandler<User>(User.class);
        //传入连接对象,sql语句,表字段和实体类属性映射关系的处理类
        List<User> userList = queryRunner.query(conn, sql, beanListHandler);
        return userList;
    }

    @Override
    public User insert(User user) throws SQLException {
        sql="insert into t_user(uname,pwd,realname,sex,address,userImg,salt)values(?,?,?,?,?,?,?)";
        BeanHandler<User> beanHandler = new BeanHandler<>(User.class);
        //执行插入后把带主键的信息返回
        user = queryRunner.insert(conn, sql, beanHandler, user.getUname(), user.getPwd(),
                user.getRealname(), user.getSex(), user.getAddress(), user.getUserImg(),
                user.getSalt());
        return user;
    }

    @Override
    public User selectByName(String uname) throws SQLException {
        sql="select * from t_user where uname=?";
        BeanHandler<User> beanHandler = new BeanHandler<>(User.class);
        User user = queryRunner.query(conn,sql,beanHandler,uname);
//        System.out.println(user);
        return user;
    }
}

service层

 

实现类

public class UserServiceImpl implements UserService {

    UserDao userDao = new UserDaoImpl();
    Digester md5=new Digester(DigestAlgorithm.MD5);

    @Override
    public List<User> selectAll() {
        try {
            return userDao.selectAll();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * 注册时需要把用户的输入密码进行MD5加密,然后存储到数据库中
     * @param user
     * @return
     */
    @Override
    public boolean insert(User user) {
        try {
            //定义加密类,设置加密规则为MD5
            Digester md5=new Digester(DigestAlgorithm.MD5);
            //MD5还可以加盐,确保密码更加安全
            String salt= UUID.randomUUID().toString().replace("-","").toUpperCase(); //随机UUID作为盐
            md5.setSalt(salt.getBytes()); //加密规则加入盐值
            //对原始密码进行MD5加密,获得加密后的密码
            String md5Pwd=md5.digestHex(user.getPwd());
            user.setPwd(md5Pwd);
            user.setSalt(salt);
            User insert = userDao.insert(user);
            if(insert!=null){
                return true;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return false;
    }
    /**
     * 登录时需要把用户输入的密码进行MD5加密后与数据库的进行比对
     * @param uname
     * @return
     */
    @Override
    public User selectByName(String uname) {
        try {
            //把原始密码进行MD5加密后比对数据库的密码
            return userDao.selectByName(uname);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }
}

验证码

方式一

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>登录页</title>
    <script src="js/jquery.min.js"></script>
    <script>
      window.onload=function(){
        var img =document.getElementById("getCode");
        img.onclick=function(){
          var date = new date().getTime();
          img.src="getCode"+date;
        }
      }
    </script>
  </head>
  <body>
  <h2>文件上传</h2>
  <!--图片上传需要设置enctype为multipart/form-data,以二进制进行传输-->
  <form action="login" method="post">
    用户:<input type="text" name="uname" value=""> <br/>
    密码:<input type="password" name="pwd" value=""><br/>
    验证码:<input type="text" name="yzm" value="">
    <img src="getCode"><a id="change" href="">看不清换一张</a> <br/>
    <input type="submit" value="登录"> <a href="register.jsp">去注册</a>
  </form>
  </body>
</html>
@WebServlet("/getCode")
public class GetCode extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //生成圆形干扰的验证码图片,设置宽度、高度、验证码数量、干扰数量
        CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(80, 30, 4, 10);
        //CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(200,100,6,100);
        // LineCaptcha captcha = CaptchaUtil.createLineCaptcha(200,100 6,100);
        //获取生成的验证码并打印输出
        String code = captcha.getCode();
//        System.out.println("随机的验证码为:"+code);
        //把验证码写入响应的输出流
        captcha.write(response.getOutputStream());
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}

效果:点击超链接切换验证码 

方式二 

@WebServlet("/getCode")
public class GetCode extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //生成圆形干扰的验证码图片,设置宽度、高度、验证码数量、干扰数量
        CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(80, 30, 4, 10);
//        CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(200,100,6,100);
//        LineCaptcha captcha = CaptchaUtil.createLineCaptcha(200,100 6,100);
//        captcha.setBackground(new Color(99,97,255));
//        captcha.setFont(new Font("隶书",1,36));
//        captcha.setTextAlpha(0.5F);
        //获取生成的验证码并打印输出
        String code = captcha.getCode();
//        System.out.println("随机的验证码为:"+code);
        //把验证码值存入session域,方便用户登录的时候进行比对
        request.getSession().setAttribute("code",code);
        //把验证码写入响应的输出流
        captcha.write(response.getOutputStream());
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}

zhuye.jsp 

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>主页</title>
    <style>
        img{
            width: 200px;
            height: 200px;
            border-radius: 50%;
        }
    </style>
</head>
<body>
<h2>欢迎来到主页!</h2>
<div>
<%--    ${user}--%>
    ${user.uname}<br/>
    <img src="${user.userImg}">
</div>
</body>
</html>

servlet层

登录和验证码判断 

@WebServlet("/login")
public class UserLogin extends HttpServlet {

    UserService userService = new UserServiceImpl();
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("utf-8");
        response.setCharacterEncoding("utf-8");

        String uname = request.getParameter("uname");
        String pwd = request.getParameter("pwd");
        String code = request.getParameter("code");
//        System.out.println(uname);
//        System.out.println(pwd);
//        System.out.println(code);
        //判断验证码
        if(code!=null && code.equals(request.getSession().getAttribute("code"))){
            User user = userService.selectByName(uname);
            if(user!=null){
                //创建加密类对象,使用MD5加密规则
                Digester md5 = new Digester(DigestAlgorithm.MD5);
                md5.setSalt(user.getSalt().getBytes());//md5加入用户的盐
                if(md5.digestHex(pwd).equals(user.getPwd())){//加盐加密后 和数据库存的安全密码一致
                    request.getSession().setAttribute("user",user);
                    response.sendRedirect("zhuye.jsp");
                }else{
                    request.setAttribute("error","密码错误!");
                    request.getRequestDispatcher("index.jsp").forward(request,response);
                }
            }else{
                request.setAttribute("error","帐号不存在!");
                request.getRequestDispatcher("index.jsp").forward(request,response);
            }
        }else{
            request.setAttribute("error","验证码错误!");
            request.getRequestDispatcher("index.jsp").forward(request,response);
        }
    }
}

效果图:点击登录跳转主页展示头像 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/606712.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

权限管理与jwt鉴权

权限管理与jwt鉴权 学习目标&#xff1a; 理解权限管理的需求以及设计思路实现角色分配和权限分配 理解常见的认证机制 能够使用JWT完成微服务Token签发与验证 权限管理 需求分析 完成权限&#xff08;菜单&#xff0c;按钮&#xff08;权限点&#xff09;&#xff0c;A…

【5.26 代随_38day】 动态规划基础理论、斐波那契数、爬楼梯、使用最小花费爬楼梯

动态规划基础理论、斐波那契数、爬楼梯、使用最小花费爬楼梯 动态规划基础理论1.动态规划的五部曲 斐波那契数1.动态规划的方法代码 爬楼梯图解步骤代码 使用最小花费爬楼梯图解步骤代码 动态规划基础理论 视频连接&#xff1a;动态规划解题方法论大曝光 &#xff01;| 理论基…

皮卡丘../../(目录遍历)/敏感信息泄露/PHP反序列化

一.目录遍历 1.概述 在web功能设计中,很多时候我们会要将需要访问的文件定义成变量&#xff0c;从而让前端的功能便的更加灵活。 当用户发起一个前端的请求时&#xff0c;便会将请求的这个文件的值(比如文件名称)传递到后台&#xff0c;后台再执行其对应的文件。 在这个过程中…

ArrayList的底层实现原理

目录 一、知识点回顾二、ArrayList 的 add() 和 remove() 的实现2.1 list.add(e) 实现原理2.2 list.remove() 实现原理 ArrayList的底层是通过数组实现的。 一、知识点回顾 数组特点&#xff1a; 存储区间是连续的&#xff0c;且占用内存严重&#xff0c;空间复杂度很大&…

第3节:cesium 离线地图下载(含教程+视频)

主要介绍两种方式。 第一种 望远网(web端地图下载) web端地图下载 第一步:选择资源发布方 第二步:选择地图类型以及路网 第三步:选择区域 支持区域选择和自定义区域两种方式 第四步:右键下载 提示:超过100个瓦片需要购买VIP

web前端 --- BOM编程、DOM编程

BOM编程&#xff08;browser object model -- 浏览器对象模型&#xff09; BOM给JavaScript提供用来操作浏览器的若干的"方法" 操作 在 js 看来&#xff0c;一个完整的浏览器包含如下组件&#xff1a; window窗口 // 整个浏览器的窗口 |-- history …

论文笔记--Efficient Estimation of Word Representations in Vector Space

论文笔记--Efficient Estimation of Word Representations in Vector Space 1. 文章简介2. 文章概括3 文章重点技术3.1 NNLM(Neural Network Language Model)3.1.1 NNLM3.1.2 RNNLM(Recurrent Neural Net Language Model) 3.2 Continuous Bag-of-Words Model(CBOW)3.3 Continuo…

皮卡丘Over Permission

1.越权漏洞概述 如果使用A用户的权限去操作B用户的数据&#xff0c;A的权限小于B的权限&#xff0c;如果能够成功操作&#xff0c;则称之为越权操作。 越权漏洞形成的原因是后台使用了不合理的权限校验规则导致的。 一般越权漏洞容易出现在权限页面&#xff08;需要登录的页面…

省三医院新门诊大楼网络安全建设项目实施方案

省三医院新门诊大楼网络安全建设项目实施方案 甲方&#xff1a;省三医院 乙方&#xff1a;武汉埃郭信息技术有限公司1组吴冰冰 项目背景 省三医院新建一栋门诊大楼&#xff0c;地址位于原三医院东南处空地。为了响应国家建设数字医疗&#xff0c;构建医联网、医共体的号召&…

不要图片?CSS实现圆角边框渐变色+背景透明

前言 &#x1f44f;不要图片&#xff1f;CSS实现圆角边框渐变色背景透明&#xff0c;最近在工作中常常实现这些效果&#xff0c;速速来Get吧~ &#x1f947;文末分享源代码。记得点赞关注收藏&#xff01; 1.实现效果 2.实现原理 border-image&#xff1a; border-image CSS …

python基本操作3(速通版)

目录 一、字典 1.字典定义 2.字典的访问 3.字典的遍历 4.字典删除 5.字典练习 6.有序字典 7.集合 8.类型转化问题 9.公共方法 二、列表推导式 1.基本操作 2.在循环中使用if 三、组包和拆包 1.组包拆包基本应用 2.拆包的字典问题 四、python函数的一些特性 1.函…

【5.31 代随_43day】 最后一块石头的重量 II、目标和、一和零

最后一块石头的重量 II、目标和、一和零 最后一块石头的重量 II1.方法图解步骤![在这里插入图片描述](https://img-blog.csdnimg.cn/d2266317bc43491fb261f6372c2e0c9d.jpeg)代码 目标和1.方法图解步骤代码 一和零图解步骤代码 最后一块石头的重量 II 力扣连接&#xff1a;104…

状态机编程应用(收放卷停车方式控制)

有关状态机的详细介绍请参看下面的文章博客: PLC面向对象编程系列之有限状态机(FSM)详解_codesys 状态机_RXXW_Dor的博客-CSDN博客编写PLC控制机器动作类程序时,当分支比较少的时候我们使用if else语句解决,当分支比较多的时候,我们要使用CASE,END_CASE语句解决,针对分支…

微信小程序个人心得

首先从官方文档给的框架说起,微信小程序官方文档给出了app.js, app.json, app.wxss. 先从这三个文件说起. 复制 app.js 这个文件是整个小程序的入口文件,开发者的逻辑代码在这里面实现,同时在这个文件夹里面可以定义全局变量.app.json 这个文件可以对小程序进行全局配置,决定…

【6.01 代随_44day】 完全背包、零钱兑换 II、组合总和 Ⅳ

完全背包、零钱兑换 II、组合总和 Ⅳ 完全背包1.方法图解步骤 零钱兑换 II1.方法图解步骤代码 组合总和 Ⅳ图解步骤代码 完全背包 讲解连接&#xff1a;完全背包 1.方法 首先再回顾一下01背包的核心代码 for(int i 0; i < weight.size(); i) { // 遍历物品for(int j b…

javaScript蓝桥杯---分阵营,比高低

目录 一、介绍二、准备三、目标四、代码五、答案 一、介绍 期末考试结束不久&#xff0c;辛勤的园丁们就将所有学生的考试成绩汇总完毕。不过现在遇到一个问题&#xff0c;那就是目前所有学生的考试数据均混杂在一起。这些数据结构如下&#xff1a; [{name: "潇然"…

安装Pygame库:在Python中创建游戏的第一步

&#x1f331;博客主页&#xff1a;大寄一场. &#x1f618;博客制作不易欢迎各位&#x1f44d;点赞⭐收藏➕关注 目录 前言 安装Pygame库 方法一、在pycharm内部直接安装 方法二、通过pip直接安装 验证安装 前言 Pygame是一个功能强大的Python游戏开发库&#xff0c;它提…

MCU器件选型---主流厂商

MCU(Micro Controller Unit)中文名称为微控制单元&#xff0c;又称单片微型计算机(Single Chip Microcomputer)&#xff0c;是指随着大规模集成电路的出现及其发展&#xff0c;将计算机的CPU、RAM、ROM、定时数器和多种I/O接口集成在一片芯片上&#xff0c;形成芯片级的计算机&…

SSRF漏洞、SQL注入、CSRF漏洞、XXE漏洞

SSRF漏洞 1.我理解的定义&#xff1a; 攻击者将伪造的服务器请求发给一个用户&#xff0c;用户接受后&#xff0c;攻击者利用该安全漏洞获得该用户的相关信息 2.原理&#xff1a; 3.场景&#xff1a; &#xff08;1&#xff09;分享 &#xff08;2&#xff09;转码 &#xff…

网络编程知识点总结(4)

sock服务端代码实现读写 前几章有具体介绍这几个函数&#xff0c;这里就简单罗列出来了 &#xff08;1&#xff09;socket()函数 int socket(int domain, int type, int protocol); &#xff08;2&#xff09;bind()函数: IP号端口号与相应描述字赋值函数 int bind(int soc…