Java web文件的上传和下载、注解

1、文件上传

  • 文件上传:将客户端的文件,保存到服务器端,比如在用户注册的时候要求用户上传一张图片作为该账号的头像;
  • 对表单限制:

1、提交方式method必须为post ,因为post请求提交的请求体大小不受限制;
2、表单的属性enctype必须为:multipart/form-data
enctype:指表单发送数据的编码方式;

  • application/x-www-form-urlencoded:数据进行URL编码
  • text/plain:纯文本发送
  • multipart/form-data:可以发送二进制数据,专门用于文件上传
  • 对Servlet限制:

1、request.getParameter()方法不能使用了,即使用了也获取的是null
2、使用request.getInputStream()来获取所有消息体数据,然后解析;

  • 解析消息体数据:使用commons-fileupload 组件解析消息体,它是Apache组织为了方便我们解析文件数据提供的第三方jar包;

为什么使用第三方jar包,因为使用request.getInputStream()获得的所有消息体数据,假如表单中还有文本框中的数据,我们应该怎么解析?从什么地方开始是文件的那部分字节数据都是不得而知的;

  • 步骤:

1、导入jar包,注意:还需要导入commons-io.jar
在这里插入图片描述
2、创建解析器工厂
3、获取解析器
4、解析request对象,返回List<FileItem> (表单项对象集合)
5、遍历集合,获取每一个表单项,获取数据

  • FileItem对象的方法:
判断是否是普通表单项:isFormField()
获取表单项name名称:getFieldName()
普通表单项的方法:
获取表单项的值:getString(String encoding)
文件表单项的方法:
获取文件名称:getName()
获取文件类型:getContentType()
获取文件大小:getSize()
获取文件关联的输出流:getOutputStream()
将文件数据写入硬盘:write(File file)

后台Java代码:

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.UUID;

@WebServlet(value = "/demoupload")
public class ServletUpLoad extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        try {
            request.setCharacterEncoding("utf-8");
            String realPath = request.getServletContext().getRealPath("/upload");
            File file = new File(realPath);
            //创建出我们要保存上传文件的文件夹
            if (!file.exists()) {
                file.mkdirs();
            }

            DiskFileItemFactory df = new DiskFileItemFactory();
            ServletFileUpload upload = new ServletFileUpload(df);
            List<FileItem> list = upload.parseRequest(request);

            for (FileItem fileItem : list) {
                //判断是否为普通的表单项
                if (fileItem.isFormField()) {
                    //获取键值
                    String name = fileItem.getFieldName();
                    String value = fileItem.getString("utf-8");
                    request.setAttribute("username", value);
                } else {
                    String name = fileItem.getFieldName();
                    //获取上传来的文件名
                    String fileName = fileItem.getName();
                    fileName = UUID.randomUUID().toString().replace("-", "") + fileName;

                    //保存传上来的文件
                    File file1 = new File(file, fileName);
                    fileItem.write(file1);

                    System.out.println("上传来的文件保存在:" + file1.getAbsolutePath());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

前台JSP代码:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<form action="${pageContext.servletContext.contextPath}/demoupload" enctype="multipart/form-data" method="post">
    用户名:<input type="text" placeholder="请输入用户名" name="username" value=""><br>
    文件名:<input type="file" name="fileName"><br>
    <input type="submit" value="提交">
</form>
</body>
</html>

在这里插入图片描述
在这里插入图片描述

2、文件下载

  • 文件下载:服务器端保存到客户端,比如我们在网页上下载一张图片保存在本地;
  • 下载方式:

1、超链接直接指向目标资源下载:如果浏览器可以解析目标文件,则直接在浏览器中打开;反之,则弹出下载提示框;

2、通过Servlet实现下载

  • 超链接指向servlet,传递目标资源的标识符。
  • 定义Servlet:
    1.获取文件标识,找到文件对象
    2.创建输入流,关联目标文件
    3.设置响应头:
content-disposition:消息体数据的打开方式
>content-disposition:attachment;filename=xxx
>content-type:类型

3.将输入流数据写入response输出流中;

  • 下载细节:

1、如果文件名是中文,有的浏览器可能会乱码,怎么处理:

if (agent.contains("MSIE")) {
    // IE浏览器
    filename = URLEncoder.encode(filename, "utf-8");
    filename = filename.replace("+", " ");
} else if (agent.contains("Firefox")) {
    // 火狐浏览器
    BASE64Encoder base64Encoder = new BASE64Encoder();
    filename = "=?utf-8?B?"
            + base64Encoder.encode(filename.getBytes("utf-8")) + "?=";
} else if (agent.contains("Chrome")) {
    // google浏览器
    filename = URLEncoder.encode(filename, "utf-8");
} else {
    // 其它浏览器
    filename = URLEncoder.encode(filename, "utf-8");
}

后台Java代码:

import org.apache.commons.io.IOUtils;
import sun.misc.BASE64Encoder;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URLEncoder;

@WebServlet(value = "/demodownload")
public class ServletDownLoad extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("utf-8");

        //首先获取这个图片的名字,前台通过请求参数给你传递过来了
        String filename = request.getParameter("filename");
        //获取服务器端该文件的路径
        String realPath = this.getServletContext().getRealPath("/WEB-INF/img/" + filename);
        FileInputStream in = new FileInputStream(realPath);
        ServletOutputStream out = response.getOutputStream();

        //解决文件名为中文的问题
        String agent = request.getHeader("user-agent");
        if (agent.contains("MSIE")) {
            // IE浏览器
            filename = URLEncoder.encode(filename, "utf-8");
            filename = filename.replace("+", " ");
        } else if (agent.contains("Firefox")) {
            // 火狐浏览器
            BASE64Encoder base64Encoder = new BASE64Encoder();
            filename = "=?utf-8?B?"
                    + base64Encoder.encode(filename.getBytes("utf-8")) + "?=";
        } else if (agent.contains("Chrome")) {
            // google浏览器
            filename = URLEncoder.encode(filename, "utf-8");
        } else {
            // 其它浏览器
            filename = URLEncoder.encode(filename, "utf-8");
        }

        //设置响应头:告诉浏览器,不要默认打开,而是弹出一个下载框。
        response.setHeader("content-disposition", "attachment;filename="
                + filename);
        //设置文件的类型
        response.setHeader("content-type", this.getServletContext()
                .getMimeType(filename));

        //流的对拷
        IOUtils.copy(in, out);
        in.close();
        out.close();
    }

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

前台JSP代码:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <a href="${pageContext.servletContext.contextPath}/demodownload?filename=首页.png">点击这里下载图片</a>
</body>
</html>

在这里插入图片描述
在这里插入图片描述

3、用户登陆注册时的显示头像

  • 需求:用户在注册的时候上传一张图片作为头像,在用户登陆的时候,使用Ajax异步请求,判断用户是否存在,如果存在从数据库中取出该用户头像的路径,通过服务器传给客户端;如果用户不存在,展示一张默认的图片;

后台代码:

----登陆:

import org.westos.domain.User;
import org.westos.service.userServiceImpl;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

@WebServlet(name = "LoginServlet", value = "/login")
public class LoginServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);

    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        try {
            request.setCharacterEncoding("utf-8");
            response.setContentType("text/html;charset=utf-8");

            //从前台取出数据
            String username = request.getParameter("username");
            String pwd = request.getParameter("pwd");
            //判断用户是否勾选了记住密码
            String remember = request.getParameter("remember");

            //创建user对象
            User user = new User();
            user.setUsername(username);
            user.setPassword(pwd);
            //System.out.println(user);

            userServiceImpl userService = new userServiceImpl();
            boolean flag = userService.loginUser(user);

            //如果登陆成功
            if (flag) {
                //创建session对象
                HttpSession session = request.getSession();

                //如果勾选了保存密码,下次帮用户自动填写
                if (remember != null && remember.equals("yes")) {
                    session.setAttribute("username", username);
                    session.setAttribute("pwd", pwd);
                }

                //如果用户先注册,再登陆,即使没有选择保存密码,之前的代码也给你保存了,你这里移除一下数据,他下次不会帮你自动补上
                if (remember == null && session.getAttribute("username") != null && session.getAttribute("pwd") != null) {
                    session.removeAttribute("username");
                    session.removeAttribute("pwd");
                }

                //内部转发
                session.setAttribute("name",username);
                request.getRequestDispatcher("index.jsp").forward(request, response);
            } else {
                //将错误信息放在请求域对象当中
                request.setAttribute("msg", "用户名或密码错误");
                //页面内部转发到当前页面
                request.getRequestDispatcher("login.jsp").forward(request, response);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

-----注册:

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.westos.domain.User;
import org.westos.service.userService;
import org.westos.service.userServiceImpl;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.List;

@WebServlet(name = "RegisterServlet", value = "/register")
public class RegisterServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //注册的逻辑:
        /*
         * 1、前台提交之后,仍然判断用户是否存在、验证码是否正确以及图像是否符合要求
         * 2、将符合要求的用户信息存入user对象当中,如果用户注册成功,跳转到登陆页面,否则跳转到注册页面
         * 3、都是使用内部转发的方式跳转
         * */

        try {
            //设置请求的编码格式
            request.setCharacterEncoding("utf-8");
            //使用第三方工具解析带有文件的表单数据
            DiskFileItemFactory df = new DiskFileItemFactory();
            ServletFileUpload upload = new ServletFileUpload(df);
            List<FileItem> list = upload.parseRequest(request);

            //创建user对象
            User user = new User();
            //创建该对象,方便二次校验
            userService userService = new userServiceImpl();

            //调用方法,帮我们判断表单项是否符合要求,最终返回user对象,如果不为 null,就表示用户注册成功
            User getUser = userService.parseListGetUser(list, request);

            //如果用户不存在、验证码正确、文件符合要求,就注册该用户
            if (getUser != null) {
                //如果用户返回的不为null,代表注册成功

                //保存session信息,这样用户在登录的时候直接展示了个人信息
                HttpSession session = request.getSession();
                session.setAttribute("username", user.getUsername());
                session.setAttribute("pwd", user.getPassword());
                session.setAttribute("imgUrl", user.getPicture());
                //内部转发到登陆页面
                request.getRequestDispatcher("login.jsp").forward(request, response);
            } else {
                //如果有一个出现了差错,内部转发到空页面
                request.getRequestDispatcher("empty.jsp").forward(request, response);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

前台代码:

----登陆页面:

<%--
  Created by IntelliJ IDEA.
  User: lenovo
  Date: 2020/8/18
  Time: 21:32
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>用户登陆</title>
    <link rel="icon" href="${pageContext.servletContext.contextPath}/aa.ico"
          mce_href="${pageContext.servletContext.contextPath}/aa.ico"
          type="image/x-icon">
    <link rel="shortcut icon" href="${pageContext.servletContext.contextPath}/aa.ico"
          mce_href="${pageContext.servletContext.contextPath}/aa.ico" type="image/x-icon">
    <style type="text/css">
        input[type="submit"] {
            background-color: #0d65d0;
            color: white;
            border: 0px;
            width: 100px;
            height: 40px;
            font-size: 18px;
        }

        input {
            height: 30px;
        }

        td {
            font-family: Microsoft YaHei;
        }

        span {
            font-size: 14px;
        }
    </style>
</head>
<body>
<center>
    <h1>登陆页面</h1>
    <form action="${pageContext.servletContext.contextPath}/login" method="post" onsubmit="return check()">
        <table border="0" cellspacing="0" cellpadding="0" width="500px" height="300px">
            <tr>
                <td colspan="2">
                    <div style="border: 0px black solid;margin: auto; width: 20%;height: 40px;">
                        <img src="${pageContext.servletContext.contextPath}/upload/google.png"
                             style="max-width: 100%;max-height: 100%;" id="myPicture">
                    </div>
                </td>
            </tr>
            <tr>
                <td style="text-align: right;">用户名:</td>
                <td><input type="text" name="username" placeholder="请输入用户名" style="width: 60%;" onchange="checkName()"
                           id="username" value="${sessionScope.username}"/>
                    <span id="myspan1" style="color: #ff0000"></span></td>
            </tr>
            <tr>
                <td style="text-align: right;">密码:&nbsp;&nbsp;&nbsp;</td>
                <td><input type="password" name="pwd" placeholder="请输入密码" style="width: 60%;" id="pwd"
                           onchange="checkPwd()"
                           value="${sessionScope.pwd}"/><span
                        id="myspan2" style="color: red"></span></td>
            </tr>
            <tr>
                <td colspan="2">
                    <input type="checkbox" name="remember" value="yes" id="remember"
                           style="text-align:right;vertical-align: middle;margin-left: 70%;">
                    <label style="font-size: 14px;cursor: pointer" for="remember">记住密码</label></td>
                <td></td>
            </tr>
            <tr>
                <td colspan="2">
                    <input type="submit" value="登陆" style="margin-left: 40%"/>
                    <a href="${pageContext.servletContext.contextPath}/register.jsp"
                       style="font-size: 13px;margin-left: 10px;">没有账号,请先注册</a>
                </td>
                <td></td>
            </tr>
            <tr>
                <td colspan="2">
                    <div style="color: red;margin-left: 40%;">
                        ${requestScope.msg}
                    </div>
                </td>
                <td></td>
            </tr>
        </table>
    </form>
</center>
</body>
<script>
    //之前的用户名和密码都是通过域对象取出来的,但是这里src已经被占用了,你页面一加载,就调用一次方法
    //如果用户名已经填写了,它会自动根据用户名加载
    getPicture();

    /*onblur 事件处理程序:当元素或窗口失去焦点时触发该事件
    onchange事件处理程序:当表单元素获取焦点,并且内容发生改变时,触发该事件*/
    function checkName() {
        var uname = document.getElementById("username");
        var span1 = document.getElementById("myspan1");
        if (!uname.value.trim()) {
            span1.innerText = "用户名不能为空!";
            uname.focus();
            return false;
        } else {
            span1.innerText = "";

            //如果用户名已经填入,光标一离开,
            //我们做Ajax异步请求,将数据传给后台,查询数据库,是否存在该用户
            //我们下来进行异步提交

            //1、创建Ajax请求对象
            xmlhttp = new XMLHttpRequest();
            //post请求的请求参数,不能拼接在地址栏后面
            //http://localhost:8080/login 绝对路径

            //2、自己服务器里面的前台页面,请求自己服务器里面的后台Servlet 不需要写绝对路径
            xmlhttp.open("POST", "${pageContext.servletContext.contextPath}/judgeName", true); //相对路径
            //3.设置请求头信息
            xmlhttp.setRequestHeader('content-type', 'application/x-www-form-urlencoded');
            //4、发送请求post请求的参数传递给请求体带给后台
            //ES6语法字符串中填充变量
            // alert(uname.value.trim());
            xmlhttp.send("uname=" + uname.value.trim());
            xmlhttp.onreadystatechange = function () {
                //200 响应状态码 200表示后台成功响应你了
                if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
                    //5、接收后台响应的字符串
                    var jsonStr = xmlhttp.responseText;
                    //6、解析json字符串
                    var jsonObj = JSON.parse(jsonStr);
                    //7、判断返回结果并展示页面
                    if (jsonObj.hasUser == 'no') {
                        span1.innerText = "用户不存在";
                        //清空input框中的文本,并获取光标

                        //给图片的src任然置为默认的图片
                        document.getElementById("myPicture").src = "${pageContext.servletContext.contextPath}/upload/google.png";

                        uname.innerText = "";
                        uname.focus();
                        return false;
                    } else if (jsonObj.hasUser == 'yes') {
                        getPicture();
                        span1.innerText = "";
                    }
                }
            }
        }
        return true;
    }

    function getPicture() {
        //alert("进来没?");
        //发送Ajax,根据用户名获得头像
        var uname = document.getElementById("username");
        var picture = document.getElementById("myPicture");
        //alert(picture.src);

        //1、创建Ajax请求对象
        xmlhttp = new XMLHttpRequest();
        //post请求的请求参数,不能拼接在地址栏后面
        //http://localhost:8080/login 绝对路径

        //2、自己服务器里面的前台页面,请求自己服务器里面的后台Servlet 不需要写绝对路径
        xmlhttp.open("POST", "${pageContext.servletContext.contextPath}/getPicture", true); //相对路径
        //3.设置请求头信息
        xmlhttp.setRequestHeader('content-type', 'application/x-www-form-urlencoded');
        //4、发送请求post请求的参数传递给请求体带给后台
        // alert(uname.value.trim());
        xmlhttp.send("uname=" + uname.value.trim());
        xmlhttp.onreadystatechange = function () {
            //200 响应状态码 200表示后台成功响应你了
            if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
                //alert(xmlhttp.responseText);
                //5、接收后台响应的字符串
                var jsonStr = xmlhttp.responseText;
                //alert(jsonStr+"json字符串本来的样子");
                //6、解析json字符串
                var jsonObj = JSON.parse(jsonStr);
                //7、判断返回结果并展示页面
                //alert(jsonObj.myfilename+"JSON解析后");

                picture.src = "${pageContext.servletContext.contextPath}" + jsonObj.myfilename;
                //alert(picture.src)
            }
        }
    }

    function checkPwd() {
        var pwd = document.getElementById("pwd");
        var span2 = document.getElementById("myspan2");
        if (!pwd.value.trim()) {
            span2.innerText = "密码不能为空!";
            pwd.focus();
            return false;
        } else {
            span2.innerText = "";
        }
        return true;
    }

    function check() {
        return checkName() && checkPwd();
    }
</script>
</html>

-----注册页面:

<%--
  Created by IntelliJ IDEA.
  User: lenovo
  Date: 2020/8/18
  Time: 21:33
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>用户注册</title>
    <link rel="icon" href="/myLogin_Register_war_exploded/aa.ico" mce_href="/myLogin_Register_war_exploded/aa.ico"
          type="image/x-icon">
    <link rel="shortcut icon" href="/myLogin_Register_war_exploded/aa.ico"
          mce_href="/myLogin_Register_war_exploded/aa.ico"
          type="image/x-icon">
    <script src="jquery-3.3.1.js"></script>
    <style type="text/css">
        input[type="submit"] {
            background-color: #0d65d0;
            color: white;
            border: 0px;
            width: 100px;
            height: 40px;
            font-size: 18px;
        }

        input {
            height: 30px;
        }

        td {
            font-family: Microsoft YaHei;
        }

        span {
            font-size: 14px;
        }
    </style>
</head>
<body>
<center>
    <h1>注册页面</h1>
    <form action="${pageContext.servletContext.contextPath}/register" enctype="multipart/form-data" method="post"
          onsubmit="return check()">
        <table border="0" cellspacing="0" cellpadding="0" width="520px" height="500px">
            <tr>
                <td>用户名:</td>
                <td><input type="text" name="username" placeholder="请输入用户名" style="width: 70%;" id="username"
                           onchange="checkName()"/><span
                        id="myspan1" style="color: red"></span></td>
            </tr>
            <tr>
                <td>密码:</td>
                <td><input type="password" name="pwd" placeholder="请输入密码" style="width: 90%;" id="pwd"
                           onchange="checkPwd()"/></td>
            </tr>
            <tr>
                <td>确认密码:</td>
                <td><input type="password" name="repwd" placeholder="请重复输入密码" style="width: 90%;" id="repwd"
                           onchange="checkRepwd()"/></td>
            </tr>
            <tr>
                <td>电话:</td>
                <td><input type="tel" name="tel" value="" placeholder="请输入电话号码" style="width: 90%;"
                           onchange="checkTel()" id="tel"/></td>
            </tr>
            <tr>
                <td>邮箱:</td>
                <td><input type="email" name="email" placeholder="请输入邮箱" style="width: 90%;" onchange="checkEmail()"
                           id="email"/>
                </td>
            </tr>

            <tr>
                <td>性别:</td>
                <td>
                    <input type="radio" name="sex" id="0" value="男" style="vertical-align: middle;"
                           checked="checked"/><label for="0"></label>
                    &nbsp;

                    <input type="radio" name="sex" id="1" value="女" style="vertical-align: middle;"/><label
                        for="1"></label>
                </td>
            </tr>
            <tr>
                <td>出生日期:</td>
                <td><input type="date" name="birthday" value="" style="width: 90%;"/></td>
            </tr>
            <tr>
                <td>爱好:</td>
                <td><input type="checkbox" name="hobby" id="song" value="唱歌" style="vertical-align: middle;"
                           checked="checked"/><label
                        for="song">唱歌</label>
                    <input type="checkbox" name="hobby" id="sport" value="运动" style="vertical-align: middle;"/><label
                            for="sport">运动</label>
                    <input type="checkbox" name="hobby" id="read" value="阅读" style="vertical-align: middle;"/><label
                            for="read">阅读</label>
                </td>
            </tr>
            <tr>
                <td>上传头像:</td>
                <td colspan="0">
                    <input type="file" name="file" id="picture" value="" onchange="checkPicture()"/><span
                        id="myspan2" style="color: red"></span>
                </td>
            </tr>
            <tr>
                <td>验证码:</td>
                <td colspan="3">
                    <input type="text" name="code" placeholder="请输入验证码" id="code" onchange="checkCode()"/>
                    <img src="${pageContext.servletContext.contextPath}/code"
                         style="width: 100px;height: 30px;border: 1px black solid;margin-bottom: -10px;"
                         id="img" onclick="switchCode()">
                    <a href="#" style="font-size: 15px;font-family: Microsoft YaHei;margin-left: 10px;"
                       onclick="switchCode()">看不清?换一张</a></td>
            </tr>
            <tr>
                <td colspan="2">
                    <center><input type="submit" value="注册"/></center>
                </td>
                <td></td>
            </tr>
        </table>
    </form>
</center>
</body>
<script>
    function switchCode() {
        var img = document.getElementById("img");
        //欺骗服务器
        img.src = "${pageContext.servletContext.contextPath}/code?" + new Date().getTime();
    }

    function check() {
        //alert("进来没?");
        return checkName() && checkPwd() && checkRepwd() && checkEmail() && checkTel() && checkCode() && b;
    }

    function checkName() {
        var name = document.getElementById("username");
        var span1 = document.getElementById("myspan1");
        if (name.value.trim().length == 0) {
            alert("用户名不能为空!");
            name.focus();
            return false;
        } else {
            //我们下来进行异步提交

            //1、创建Ajax请求对象
            xmlhttp = new XMLHttpRequest();
            //post请求的请求参数,不能拼接在地址栏后面
            //http://localhost:8080/login 绝对路径

            //2、自己服务器里面的前台页面,请求自己服务器里面的后台Servlet 不需要写绝对路径
            xmlhttp.open("POST", "${pageContext.servletContext.contextPath}/judgeName", true); //相对路径
            // xmlhttp.open("POST", "/LoginAndRegister_war_exploded/judge?uname=" + name.value.trim(), true);
            //3.设置请求头信息
            xmlhttp.setRequestHeader('content-type', 'application/x-www-form-urlencoded');
            //4、发送请求post请求的参数传递给请求体带给后台
            //ES6语法字符串中填充变量
            // alert(name.value.trim());
            xmlhttp.send("uname=" + name.value.trim());
            xmlhttp.onreadystatechange = function () {
                //200 响应状态码 200表示后台成功响应你了
                if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
                    //5、接收后台响应的字符串
                    var jsonStr = xmlhttp.responseText;
                    //6、解析json字符串
                    var jsonObj = JSON.parse(jsonStr);
                    //7、判断返回结果并展示页面
                    if (jsonObj.hasUser == 'no') {
                        span1.innerText = "";
                    } else if (jsonObj.hasUser == 'yes') {
                        span1.innerText = "用户已经存在";
                        //清空input框中的文本,并获取光标
                        name.innerText = "";
                        name.focus();
                        return false;
                    }
                }
            }
        }
        return true;
    }

    function checkPwd() {
        var pwd = document.getElementById("pwd");
        if (pwd.value.trim().length == 0) {
            alert("密码不能为空!");
            pwd.focus();
            return false;
        }
        return true;
    }

    function checkRepwd() {
        var pwd = document.getElementById("pwd");
        var repwd = document.getElementById("repwd");
        if (repwd.value.trim().length == 0 || repwd.value != pwd.value) {
            alert("两次输入的密码不一致!");
            repwd.focus();
            return false;
        }
        return true;
    }

    function checkTel() {
        var re = /^1\d{10}$/;
        var tel = document.getElementById("tel");
        if (!re.test(tel.value.trim())) {
            alert("电话号码格式错误!");
            tel.focus();
            return false;
        }
        return true;
    }

    function checkEmail() {
        var re = /^(\w-*\.*)+@(\w-?)+(\.\w{2,})+$/;
        var email = document.getElementById("email");
        if (!re.test(email.value.trim())) {
            alert("邮箱格式错误!");
            email.focus();
            return false;
        }
        return true;
    }

    function checkCode() {
        var code = document.getElementById("code");
        if (code.value.trim().length == 0) {
            alert("请输入验证码!");
            code.focus();
            return false;
        } else {
            //我们下来进行异步提交

            //1、创建Ajax请求对象
            xmlhttp = new XMLHttpRequest();
            //post请求的请求参数,不能拼接在地址栏后面
            //http://localhost:8080/login 绝对路径

            //2、自己服务器里面的前台页面,请求自己服务器里面的后台Servlet 不需要写绝对路径
            xmlhttp.open("POST", "${pageContext.servletContext.contextPath}/judgeCode", true); //相对路径
            //3.设置请求头信息
            xmlhttp.setRequestHeader('content-type', 'application/x-www-form-urlencoded');
            //4、发送请求post请求的参数传递给请求体带给后台
            //ES6语法字符串中填充变量:有问题!
            xmlhttp.send("code=" + code.value.trim());
            xmlhttp.onreadystatechange = function () {
                //200 响应状态码 200表示后台成功响应你了
                if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
                    //5、接收后台响应的字符串
                    var jsonStr = xmlhttp.responseText;
                    //6、解析json字符串
                    var jsonObj = JSON.parse(jsonStr);
                    //7、判断返回结果并展示页面
                    if (jsonObj.codeIsRight == 'no') {
                        alert("验证码错误");

                        //重新申请一个验证码
                        switchCode();

                        //清空input框中的文本,并获取光标、
                        code.innerText = "";
                        code.focus();
                        return false;
                    }
                }
            }
        }
        return true;
    }

    var b = false;
    function checkPicture() {
        var picture = document.getElementById("picture");
        var span2 = document.getElementById("myspan2");
        if (picture.value == '') {
            alert("请选择头像!");
            return false;
        } else {
            const formData = new FormData();
            formData.append("file", picture.files[0]);
            //alert(formData);
            $.ajax({
                url: "${pageContext.servletContext.contextPath}/judgePicture",
                type: "POST",
                data: formData,
                dataType: "json",
                processData: false,  // 告诉jQuery不要去处理发送的数据
                contentType: false,   // 告诉jQuery不要去设置Content-Type请求头
                success: function (res) {
                    // console.log(res);
                    if (res.pictureIsRight == 'no') {
                        //如果图片不符合要求
                        span2.innerText = "图片不符合要求,请重新选择";
                    } else if (res.pictureIsRight == 'yes') {
                        //如果图片符合要求
                        //alert("res.pictureIsRight == 'yes'");
                        span2.innerText = "";
                        b = true;
                    }
                }
            });
        }
        return b;
    }
</script>
</html>

在这里插入图片描述

4、注解

  • 注解(Annotation),也叫元数据,一种代码级别的说明,注解是给程序看的;
  • 它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。
  • 它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
  • 格式:
@interface 注解名{}
  • 作用:

编译检查
替代配置文件,框架中很多注解为了简化配置;
定义注解(元注解:注解上的注解)

  • Java中3个常见的注解:

1、@Override注解

他是用来声明该方法是重写了父类的方法,执行编译期的检查;

2、@SuppressWarnings

抑制警告,值有很多,只需要知道一个 all,抑制所有的警告

@SuppressWarnings("all")
public class MyTest {
    public static void main(String[] args) {
        int a;
    }
}

在这里插入图片描述
3、@Deprecated

用于声明该方法不赞成使用,标志过时;

在这里插入图片描述

  • 注解属性:

注解本身使用@interface来定义;

注解本质就是一个接口,可以用javap这个命令反编译一下,注解的字节码文件,例如javap myan.class

在接口中可以有常量和抽象方法,抽象方法在注解中就称之为注解属性

public @interface MyAnnotation {
	//注解本质上是一个接口,那接口中的抽象方法,其实就是注解中的属性
    public abstract String name(); //注解的属性,前面的public abstract 可以省略
    int hehe();  //前面的数据类型,不是所有类型都支持
  	Class haha();
}

在这里插入图片描述
由上图可知,注解本身是一个接口类,继承自Annotation类;

  • 注解属性支持的类型如下:
基本类型
String
Class
Annotation
Enum:枚举
以上类型对应的一维数组
  • 注意:

一旦注解有属性了,使用注解的时候必须赋值,(除非这个注解属性有默认值)

public @interface MyAnnotation {
	int hehe();  //注意我这个注解有属性了
}

那么我在另一个类上添加我自定义的注解就会报错,因为我注解中的属性没有赋值

@MyAnnotation()  //报错,要不报错括号里面要赋值,除非有默认值
public class Test {
}

下面就是正确的:

 @MyAnnotation(hehe=100)   //给注解中属性赋值,就不报错了
public class Test {
}

注解中有多个属性,在给属性赋值时,用逗号隔开;并且一个注解也可以赋多个属性值,这时候使用大括号包裹属性值,属性值之间使用逗号隔开;

public @interface MyAnnotation {
	int hehe();  //注意我这个注解有属性了
	String haha();
	int[] num();
}
//多个属性赋值
@MyAnnotation(hehe=100,haha='abc',num={10,20})   
//给注解中属性赋值,就不报错了
public class Test {
}

赋值的格式:

@注解名(属性名=属性值)
若注解类型为数组,且只有一个值的时候,可以有两种写法
	方式1:
		属性名 = {}
	方式2:
		属性名=属性值

注意特殊情况若属性名为value的时候,且只需要为这个value属性赋值的时候,value可以省略;

public @interface MyAnnotation {
	String value(); //这个属性名叫value 比较特殊
}

注解中的属性名为value时,赋值时可以省略value;

@MyAnnotation("zhangsan")  //属性名为value时可以省略value
	//@MyAnnotation(value="zhangsan") 当然不省略也可以
	public class Test {
}

使用 default 关健字给属性赋上默认值

public @interface MyAnnotation {
	int num() default 100;
	String name() default "zhangsan";
}
@MyAnnotation()  //因为注解的属性中有默认值,我们可以不用赋值
public class Test {
}

与interface的区别

  • 注解基本要求:

注解是不会影响程序代码的执行,无论annotation怎么变化,代码都始终如一地执行。Java语言解释器在工作时会忽略这些annotation,因此在JVM中这些annotation是“不起作用”的,只能通过配套的工具才能对这些annontaion类型的信息进行访问和处理。

  • Annotation与interface的异同:

1、Annotation类型使用关键字@interface而不是interface。继承了java.lang.annotation.Annotation接口,并非声明了一个interface;
2、Annotation类型、方法定义是独特的、受限制的。Annotation类型的方法必须声明为无参数、无异常抛出的。这些方法定义的是annotation的成员:方法名成为了成员名,而方法返回值成为了成员的类型。注解方法返回值类型必须为primitive类型、Class类型、枚举类型、annotation类型或者由前面类型之一作为元素的一维数组。方法的后面可以使用default和一个默认数值来声明成员的默认值,null不能作为成员默认值,与非annotation类型中定义方法有很大不同。Annotation类型和它的方法不能使用annotation类型的参数、成员不能是generic。只有返回值类型是Class的方法可以在annotation类型中使用generic;

元注解

  • 使用注解:就是注解可以加在哪里,我们可以通过元注解,来标识我们自己定义的注解可以加在什么位置;
  • 元注解:定义在注解上的注解;

@Retention:规定注解保留到什么阶段,值为RetentionPolicy的三个枚举值

SOURCE:只在代码中保留,在字节码文件中就删除了,不会留在Class文件中。
CLASS:在代码和字节码文件中保留,但是在运行的时候,JVM不会读取。
RUNTIME:所有阶段都保留,所以它能够通过反射调用,所以正常运行时注解都是使用这个参数

@Target:规定注解作用在什么上面,值为ElementType的枚举值

TYPE:作用在类 接口 等上面
METHOD:作用方法上面
FIELD:作用字段上面
例如:
@Target(ElementType.METHOD)  //这个表示我们自定义的注解只能加在方法上
@Retention(RetentionPolicy.RUNTIME) //表示我们的注解保留到运行阶段
@interface MyAnnotation {
	  int num() default 100;
	 String name() default "zhangsan";
}

使用注解:
public class Test {
		@MyAnnotation() 这个注解只能加在方法上
		public void add(){
	}
}

需求:

通过配置四个参数获取与数据库连接的工具类;

步骤分析:

1、自定义一个注解JDBCInfo,添加元注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

//表示该注解用在运行期间
@Retention(value = RetentionPolicy.RUNTIME)
//表示该注解用在方法上
@Target(value = ElementType.METHOD)
public @interface JDBCInfo {
    String driverClass() default "com.mysql.cj.jdbc.Driver";
    String url() default "jdbc:mysql://localhost:3306/mydb?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC&useSSL=false";
    String user() default "root";
    String password() default "123456";
}

2.在jdbcutils工具类中提供一个getConnection,在方法上面添加一个注解@JDBCInfo(...)

import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class JDBCUtils {
    @JDBCInfo
    public static Connection getConnection() throws NoSuchMethodException, ClassNotFoundException, SQLException {
        //获取当前类的字节码文件对象
        Class<JDBCUtils> jdbcUtilsClass = JDBCUtils.class;
        //获取方法对象
        Method method = jdbcUtilsClass.getMethod("getConnection");
        //判断上述方法是否有注解,如果有的话获取注解,并拿到注解的属性值
        //参数是注解的class对象
        boolean b = method.isAnnotationPresent(JDBCInfo.class);
        //获取注解
        if(b){
            JDBCInfo info = method.getAnnotation(JDBCInfo.class);
            //获取注解的属性值
            String driverClass = info.driverClass();
            String url = info.url();
            String user = info.user();
            String password = info.password();

            //加载数据库驱动
            Class.forName(driverClass);
            return DriverManager.getConnection(url,user,password);
        }
        return null;
    }
}

3.运行的时候可以通过getConnection获取一个连接

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class MyTest3 {
    public static void main(String[] args) throws NoSuchMethodException, SQLException, ClassNotFoundException {
        Connection conn = JDBCUtils.getConnection();
        PreparedStatement statement = conn.prepareStatement("select * from dallas_dept");
        ResultSet resultSet = statement.executeQuery();
        while (resultSet.next()) {
            String dept_no = resultSet.getString(1);
            String dept_name = resultSet.getString(2);
            System.out.println(dept_no + "-----------" + dept_name);
            /*d1-----------Research
            d3-----------Sales*/
        }
        conn.close();
        statement.close();
    }
}
  • servlet 3.0开始,支持注解开发,没有web.xml这个文件了,内嵌了文件上传功能;比如我们创建servlet,在Servlet类上面添加 @WebServlet(urlPatterns="/demo2"),一个Servlet也可以配置多个映射路径,访问哪一个都行,urlPatterns这个注解属性是个数组,所以可以配置多个值@WebServlet(urlPatterns={ "/demo2", "/demo21" },loadOnStartup=2);它的作用与value的作用是一样的;但是注解不能完全替代配置文件,它只是起到了一个简化的作用;
@WebServlet(name = "ServletDemo1",urlPatterns = {"/demo1","/demo2","/demo3"},initParams = {@WebInitParam(name = "num",value = "100")},loadOnStartup = 0)
  • 在servlet的注解@WebServlet中,有一个参数也是注解,意味着如果要给这个参数赋值,必须给定一个注解类型:

在这里插入图片描述
在这里插入图片描述

代码:

import javax.servlet.ServletException;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet(name = "MyServlet", value = "/my",initParams = {@WebInitParam(name = "init",value = "/init"),@WebInitParam(name = "init2",value = "/init2")})
public class MyServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取注解的值
        String init = this.getInitParameter("init");
        System.out.println(init);
        String init2 = this.getInitParameter("init2");
        System.out.println(init2);
        /*/init
        /init2*/
    }
}
©️2020 CSDN 皮肤主题: 技术工厂 设计师:CSDN官方博客 返回首页