Servlet

目录

一,概念

1.什么是Servlet

2.servlet能干什么

二,访问出错

1.404

2.405

3.500

4.出现空白页面

5.无法访问此网站

6.小结

三,Servlet的API详解

1.HttpServletRequest

1)核心方法

2)方法示例(以queryString形式演示)

3)getParameter方法

4)getPart

5)getInputStream

2.HttpServletResponse

1)核心方法

2)setStatus方法

3)重定向与转发

4)返回一个文件

5)返回json数据

四,session和cookie


一,概念

1.什么是Servlet

  • Servlet 是一种实现动态页面的技术. 是一组 Tomcat 提供给程序猿的 API, 帮助程序猿简单高效的开发一个 web app
  • 为不同的Java web服务器规定了相应的编程规范(官方规范),定义好了统一的编程规范(统一的类,接口,方法)
  • 屏蔽了不同web服务器的细节(实现的细节,体现在对请求的解析,响应的封装)
  • 更换一个web服务器,web应用程序还可以使用

2.servlet能干什么

servlet就是以编程的方式,提供对请求的处理,以及响应的内容(状态码,header,body)

  • html是静态文件,要想访问动态页面,servlet才可以
  • 文件下载,servlet也可以
  • 用户登录,服务端需要对账号密码进行验证,验证成功才可以跳转,servlet才可以

二,访问出错

1.404

404 表示用户访问的资源不存在. 大概率是 URL 的路径写的不正确

1)少写了 Context Path(应用上下文路径/应用名)

2)少写了Servlet Path(资源路径)

3)Servlet Path 写的和 URL 不匹配

4)web.xml 写错了

2.405

405 表示对应的 HTTP 请求方法没有实现

1)没有实现 doGet 方法.

2)如果是post请求,没有实现post方法,也会报405的错

3.500

往往是 Servlet 代码中抛出异常导致的(后端代码有问题)

4.出现空白页面

有实现方法,但是没有任何返回内容(空数据)

5.无法访问此网站

servlet内部有问题,资源路径写错了

或者是在资源路径前加空格等等 

6.小结

  • 4xx 的状态码表示路径不存在, 往往需要检查 URL 是否正确, 和代码中设定的 Context Path 以及Servlet Path 是否一致.
  • 5xx 的状态码表示服务器出现错误, 往往需要观察页面提示的内容和 Tomcat 自身的日志, 观察是否存在报错.
  • 出现连接失败往往意味着 Tomcat 没有正确启动, 也需要观察 Tomcat 的自身日志是否有错误提示.
  • 空白页面这种情况则需要我们使用抓包工具来分析 HTTP 请求响应的具体交互过程

三,Servlet的API详解

1.HttpServletRequest

1)核心方法

方法描述
String getProtocol()返回请求协议的名称和版本。
String getMethod()返回请求的 HTTP 方法的名称,例如,GET、POST 或 PUT。
String getRequestURI()从协议名称直到 HTTP 请求的第一行的查询字符串中,返回该请
求的 URL 的一部分。
String getContextPath()返回指示请求上下文的请求 URI 部分。
String getQueryString()返回包含在路径后的请求 URL 中的查询字符串。
Enumeration
getParameterNames()
返回一个 String 对象的枚举,包含在该请求中包含的参数的名
称。
String getParameter(String
name)
以字符串形式返回请求参数的值,或者如果参数不存在则返回
null。
String[]
getParameterValues(String
name)
返回一个字符串对象的数组,包含所有给定的请求参数的值,如
果参数不存在则返回 null。
Enumeration
getHeaderNames()
返回一个枚举,包含在该请求中包含的所有的头名。
String getHeader(String
name)
以字符串形式返回指定的请求头的值。
String
getCharacterEncoding()
返回请求主体中使用的字符编码的名称。
String getContentType()返回请求主体的 MIME 类型,如果不知道类型则返回 null。
int getContentLength()以字节为单位返回请求主体的长度,并提供输入流,或者如果长
度未知则返回 -1。
InputStream
getInputStream()
用于读取请求的 body 内容. 返回一个 InputStream 对象

2)方法示例(以queryString形式演示)

package request;

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.IOException;

@WebServlet("/request")
public class RequestStudyServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("请求协议名:"+req.getProtocol());
        System.out.println("请求方法:"+req.getMethod());
        System.out.println("应用上下文路径/应用名:"+req.getContextPath());
        System.out.println("资源路径/servletPath路径:"+req.getServletPath());

        req.setCharacterEncoding("utf-8");
        System.out.println("username:" + req.getParameter("username"));
        System.out.println("password:" + req.getParameter("password"));
        resp.getWriter().println("请求信息已经获取成功,在idea控制台查看");
    }
}

3)getParameter方法

主要是以,queryString,form表单格式,form-data简单数据类型为主

queryString

<!--链接跳转-->
    <a href="request?username=abc&password=123">get</a><br>
    <hr>

form表单

    <!--form表单-->
    <!--form表单提交,若没有设置请求方法,默认是get,会把form中的控件以name为键,输入/选择的内容为值
                     设置到queryString中-->
    <form action="request" method="post">
        <input type="text" name="username" placeholder="输入用户名"><br>
        <input type="password" name="password" placeholder="输入密码"><br>
        <input type="submit">
    </form>
    <hr>

form-data简单数据类型格式

<h3>form-data格式</h3>
    <form action="form-data-servlet" enctype="multipart/form-data" method="post">
        <input type="text" name="username" placeholder="输入用户名"><br>
        <input type="password" name="password" placeholder="输入密码"><br>
        <input type="submit">
    </form>

 但是需要注意,以form-data形式请求数据时,需要@MultipartConfig

@WebServlet("/form-data-servlet")
@MultipartConfig
public class FormData extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("utf-8");
        System.out.println("username:" + req.getParameter("username"));
        System.out.println("password:" + req.getParameter("password"));
    }
}

4)getPart

 获取form-data上传的文件

关于文件的获取,有两种途径:

  • 可以读取,通过part对象的输入流
  • 可以保存

读取:

Part head = req.getPart("head");
InputStream is = head.getInputStream();
byte[] bytes = new byte[is.available()];
is.read(bytes);
System.out.println(new String(bytes,"utf-8"));

保存:

Part head = req.getPart("head");
head.write("D://"+head.getSubmittedFileName());

5)getInputStream

获取body中的数据(常用于json格式)

前端:

    <h3>ajax提交</h3>
    <input type="text" id="ajax_username" placeholder="输入用户名"><br>
    <input type="password" id="ajax_password" placeholder="输入密码"><br>
    <button onclick="ajaxSubmit()">提交</button>
<script>
    function ajaxSubmit() {
        let username = document.querySelector("#ajax_username");
        let password = document.querySelector("#ajax_password");
        let json = {
            username:username.value,
            password:password.value
        }
        ajax({
            method:"post",
            url:"ajax-json-servlet",
            contentType: "application/json",
            body:JSON.stringify(json),
            callback:function (status,responseText) {
                alert("后端返回的是:"+status+responseText);
            }
        })
    }
    function ajax(args){
        let xhr = new XMLHttpRequest();
        xhr.onreadystatechange = function () {
            if(xhr.readyState == 4){
                args.callback(xhr.status,xhr.responseText);
            }
        }
        xhr.open(args.method,args.url);
        if(args.contentType){
            xhr.setRequestHeader("Content-Type",args.contentType);
        }
        if(args.body){
            xhr.send(args.body);
        }else{
            xhr.send();
        }
    }
</script>

后端:

package request;

import com.fasterxml.jackson.databind.ObjectMapper;

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.IOException;
import java.io.InputStream;

@WebServlet("/ajax-json-servlet")
public class AjaxJsonServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("utf-8");//获取body数据,要设置编码
        InputStream is = req.getInputStream();
//        int len = req.getContentLength();
//        byte[] bytes = new byte[len];
//        is.read(bytes);
//        System.out.println(new String(bytes,"utf-8"));
        ObjectMapper mapper = new ObjectMapper();
        User user = mapper.readValue(is,User.class);
        System.out.println(user);

    }
    static class User{
        private String username;
        private String password;

        @Override
        public String toString() {
            return "User{" +
                    "username='" + username + '\'' +
                    ", password='" + password + '\'' +
                    '}';
        }

        public String getUsername() {
            return username;
        }

        public void setUsername(String username) {
            this.username = username;
        }

        public String getPassword() {
            return password;
        }

        public void setPassword(String password) {
            this.password = password;
        }
    }
}

2.HttpServletResponse

1)核心方法

方法描述
void setStatus(int sc)为该响应设置状态码。
void setHeader(String name,
String value)
设置一个带有给定的名称和值的 header. 如果 name 已经存在,
则覆盖旧的值.
void addHeader(String
name, String value)
添加一个带有给定的名称和值的 header. 如果 name 已经存在,
不覆盖旧的值, 并列添加新的键值对
void setContentType(String
type)
设置被发送到客户端的响应的内容类型。
void
setCharacterEncoding(String
charset)
设置被发送到客户端的响应的字符编码(MIME 字符集)例如,
UTF-8。
void sendRedirect(String
location)
使用指定的重定向位置 URL 发送临时重定向响应到客户端。
PrintWriter getWriter()用于往 body 中写入文本格式数据.
OutputStream
getOutputStream()
用于往 body 中写入二进制格式数据

2)setStatus方法

前端:

<h3>设置响应状态码</h3>
<input type="text" id="Status"><br>
<button onclick="SetStatus()">提交</button>
function SetStatus() {
    let status = document.querySelector("#Status");
    window.location.href = "response?status="+status.value;
}

后端:

String status = req.getParameter("status");
resp.setStatus(Integer.parseInt(status));
resp.getWriter().write("设置成功");

3)重定向与转发

前端:

    <h3>重定向</h3>
    <a href="goto?type=1">跳转</a>
    <h3>转发</h3>
    <a href="goto?type=2">跳转</a>

 后端:

package response;

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.IOException;

@WebServlet("/goto")
public class GotoServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String type = req.getParameter("type");
        if("1".equals(type)){
            //重定向
            resp.setStatus(301);
            resp.setHeader("Location","hello.html");
            //以上代码可以简化为
//            resp.sendRedirect("hello.html");
        }else if("2".equals(type)){
            //转发
            req.getRequestDispatcher("hello.html").forward(req,resp);
        }
    }
}

区别转发forward()重定向sendRedirect()
根目录包含项目访问地址没有项目访问地址
地址栏不会发生变化会发生变化
哪里跳转服务器端进行的跳转浏览器端进行的跳转
请求域中数据不会丢失会丢失

4)返回一个文件

前端:

    <h3>获取一个图片(渲染展示)</h3>
    <img src="file?type=photo&show=1">
    <h3>获取一个音乐(渲染展示)</h3>
    <audio src="file?type=music&show=1" controls></audio>

    <h3>获取一个图片(下载)</h3>
    <a href="file?type=photo&show=0">下载</a>
    <h3>获取一个音乐(下载)</h3>
    <a href="file?type=music&show=0">下载</a>

后端:

package response;

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.io.OutputStream;
import java.nio.file.Files;

@WebServlet("/file")
public class FileServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // 获取响应对象的字节输出流
        OutputStream os = resp.getOutputStream();

        // 返回的文件类型:1.图片
        String type = req.getParameter("type");
        // 返回时的操作:1.渲染 2.下载
        String show = req.getParameter("show");

        File file = null;

        // <img src="file?type=photo&show=1">
        if("photo".equals(type)){//返回图片
            if("1".equals(show)) {
                resp.setContentType("image/jpeg");//jpg格式
            }else {
                //这样只是没有设置下载的文件名
                resp.setContentType("application/octet-stream");
            }
            file = new File("E:\\Workspace\\bite\\java43\\servlet-study\\src\\main\\resources\\head2.jpg");
        //<audio src="file?type=music&show=1" controls></audio>
        }else if("music".equals(type)){//返回音乐
            if("1".equals(show)) {
                resp.setContentType("audio/mp3");//mp3格式
            }else {
                resp.setContentType("application/octet-stream");
            }
            file = new File("E:\\Workspace\\bite\\java43\\servlet-study\\src\\main\\resources\\周杰伦 - 晴天.mp3");
        }
        //返回一个文件类型:Content-Length,body
        byte[] data = Files.readAllBytes(file.toPath());
        resp.setContentLength(data.length);//=setHeader("Content-Length", xxx)
        os.write(data);
    }
}

5)返回json数据

常用于ajax请求,返回一下数据,动态的填充网页

前端:

    <h3>获取ajax内容</h3>
    <button onclick="reach()">ajax</button>
    <div id="content"></div>
<script>
    function reach() {
        //获取content元素,准备添加内容(json)
        let content = document.querySelector("#content");
        ajax({
           method:"get",
           url:"ajax-json",
           callback:function (status,responseText) {
               console.log(responseText);
               //转化为json对象
               let array = JSON.parse(responseText);
               for (json of array){
                   //每一个json元素创建一个dom来保存信息
                   let p = document.createElement("p");
                   p.innerHTML = json.from + " 对 " + json.to + " 说 " + json.info;
                   content.appendChild(p);
               }
           }
        });
    }
    function ajax(args) {
        let xhr = new XMLHttpRequest();
        xhr.onreadystatechange = function () {
            if(xhr.readyState == 4){
                args.callback(xhr.status,xhr.responseText);
            }
        }
        xhr.open(args.method,args.url);
        if(args.contentType){
            xhr.setRequestHeader("Content-Type",args.contentType);
        }
        if(args.body){
            xhr.send(args.body);
        }else{
            xhr.send();
        }
    }
</script>

后端:

package response;

import com.fasterxml.jackson.databind.ObjectMapper;

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.IOException;
import java.util.ArrayList;
import java.util.List;

@WebServlet("/ajax-json")
public class AjaxJsonServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        List<Message> list = new ArrayList<>();
        Message m1 = new Message("小明","小红","我喜欢你!");
        Message m2 = new Message("小红","小明","你是个好人!");
        list.add(m1);
        list.add(m2);
        ObjectMapper mapper = new ObjectMapper();
        //把Java对象,转换为一个字符串
        String json = mapper.writeValueAsString(list);
        System.out.println(json);

        //设置json可以不设置Content-Length,tomcat会设置
        resp.setContentType("application/json;charset=utf-8");
        resp.getWriter().println(json);
    }
    static class Message{
        private String from;
        private String to;
        private String info;

        public Message(String from, String to, String info) {
            this.from = from;
            this.to = to;
            this.info = info;
        }

        public String getFrom() {
            return from;
        }

        public void setFrom(String from) {
            this.from = from;
        }

        public String getTo() {
            return to;
        }

        public void setTo(String to) {
            this.to = to;
        }

        public String getInfo() {
            return info;
        }

        public void setInfo(String info) {
            this.info = info;
        }
    }
}

 

四,session和cookie

制作一个简单的登录页面,和一个敏感文件(登陆成功才可以访问)

前端:

    <h3>登录页面</h3>
    <form action="login" method="post" >
        <input type="text" name="username" placeholder="输入用户名"><br>
        <input type="password" name="password" placeholder="输入密码"><br>
        <input type="submit" value="提交">
    </form>

 后端:

登录页面的后端设计(校验账号密码)

package session;

import javax.servlet.ServletException;
import javax.servlet.SessionCookieConfig;
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("/login")
public class LoginServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //登陆成功:跳转到hello.html,并且可以访问敏感资源/secret
        //登陆失败:返回错误信息,不允许访问敏感资源
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        //模拟验证账号密码
        if("abc".equals(username) && "123".equals(password)){
            //创建一个session,为登录成功的用户创建一个session
            //tomcat启动时维护了一个数据结构Map<String,Session>
            //用来保存多个用户的会话信息,键为sessionId的值(随机字符串)
            //获取当前请求的session,如果没有获取到,那就创建一个
            HttpSession session = req.getSession(true);
            //session对象本身也是一个Map结构,可以保存多组键值对的数据
            session.setAttribute("name",username);
            //跳转到登陆后的页面
            resp.sendRedirect("hello.html");
        }else{
            resp.setContentType("text/html;charset=utf-8");
            resp.getWriter().println("登陆失败");
        }
    }
}

敏感文件访问的设计

package session;

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("/secret")
public class SecretServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=utf-8");
        //获取不到session的时候,不会自动创建session,而是会返回null
        HttpSession session = req.getSession(false);
        if(session != null){
            //在session中寻找相应的用户信息,如果能找到就不为空,说明登陆成功
            //反之,就说明,没有这个用户,没有登陆成功
            String username = (String) session.getAttribute("name");
            if(username != null){
                resp.getWriter().println("登陆成功");
                return;
            }
        }
        resp.getWriter().println("登陆失败");
    }
}
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值