javaWeb基本使用

一、web.xml

web.xml是web程序中的核心

一个简单的servlet:

package com.yang.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

public class HelloServlet extends HttpServlet { // 继承HttpServlet并实现service方法
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html"); // 设置响应类型
        response.setCharacterEncoding("utf-8"); // 设置字符编码
        // 获取响应的输出流
        PrintWriter writer = response.getWriter();
        writer.println("hello servlet");
    }
}

使用web.xml方式配置servlet:

<!--注册servlet-->
<servlet>
    <servlet-name>hello</servlet-name>
    <servlet-class>com.yang.servlet.HelloServlet</servlet-class>
</servlet>
<!--servlet对应的mapping(映射)-->
<servlet-mapping>
    <servlet-name>hello</servlet-name>
    <!--访问路径-->
    <url-pattern>/hello</url-pattern>
</servlet-mapping>

使用注解方式配置servlet:

package com.yang.servlet;

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

@WebServlet("/hello")
public class HelloServlet extends HttpServlet { // 继承HttpServlet并实现service方法
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html"); // 设置响应类型
        response.setCharacterEncoding("utf-8"); // 设置字符编码
        // 获取响应的输出流
        PrintWriter writer = response.getWriter();
        writer.println("hello servlet");
    }
}

pom.xml文件添加依赖:

<dependency> 
      <groupId>javax.servlet</groupId>  
      <artifactId>javax.servlet-api</artifactId>  
      <version>3.1.0</version> 
</dependency> 

二、mapping问题

  • 一个servlet可以对应多个mapping,也就是说一个servlet可以有多个映射路径
<servlet>
    <servlet-name>hello</servlet-name>
    <servlet-class>com.yang.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>hello</servlet-name>
    <url-pattern>/hello</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>hello</servlet-name>
    <url-pattern>/hello2</url-pattern>
</servlet-mapping>

此时浏览器访问http:localhost:8080/hello和http:localhost:8080/hello2都是访问name为hello的servlet

  • 访问固定路径时,优先级比通配符的优先级高
<servlet>
    <servlet-name>hello</servlet-name>
    <servlet-class>com.yang.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>hello</servlet-name>
    <url-pattern>/hello</url-pattern>
</servlet-mapping>

<servlet>
    <servlet-name>hello02</servlet-name>
    <servlet-class>com.yang.servlet.HelloServlet02</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>hello02</servlet-name>
    <url-pattern>/*</url-pattern>
</servlet-mapping>

此时访问到的资源是name为hello的servlet

三、ServletContext

每个web程序都有一个对应的ServletContext对象,可以理解为它是当前的web应用

ServletContext对象的作用:

数据共享

在一个servlet中保存的信息,可以被另一个servlet拿到

package com.yang.servlet;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class Servlet01 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        ServletContext servletContext = this.getServletContext();
        // setAttribute方法存储信息
        servletContext.setAttribute("username","jack");
        response.setContentType("text/html;");
        response.setCharacterEncoding("utf-8");
        response.getWriter().print("存入数据到ServletContext对象中...");
    }
}
package com.yang.servlet;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

public class Servlet02 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        ServletContext servletContext = this.getServletContext();
        String username = (String) servletContext.getAttribute("username");
        response.setContentType("text/html;");
        response.setCharacterEncoding("utf-8");
        PrintWriter writer = response.getWriter();
        writer.print("从ServletContext对象中获取到username=" + username);
    }
}

web.xml:

<servlet>
    <servlet-name>servlet01</servlet-name>
    <servlet-class>com.yang.servlet.Servlet01</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>servlet01</servlet-name>
    <url-pattern>/servlet01</url-pattern>
</servlet-mapping>

<servlet>
    <servlet-name>servlet02</servlet-name>
    <servlet-class>com.yang.servlet.Servlet02</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>servlet02</servlet-name>
    <url-pattern>/servlet02</url-pattern>
</servlet-mapping>

拓展:同一个web应用中的每一个servlet和当前servlet的请求对象request都能通过getServletContext方法获取到当前web应用的servletContext对象

四、HttpServletResponse

常见应用:

  1. 向浏览器(客户端)输出信息
  2. 文件下载
  3. 响应重定向
文件下载

在webapp包下创建static目录,在static目录下创建images目录,该目录下存放需要下载的文件

package com.yang;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
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;

public class FileDownload extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 1.获取要下载文件的路径
        String realPath = this.getServletContext().getRealPath("/static/images/文件下载.png");

        // 2.根据路径获取下载的文件名
        String[] pathArr = realPath.split("\\\\");
        String fileName = pathArr[pathArr.length - 1];

        // 3.设置浏览器支持文件下载
        // URLEncoder.encode(fileName,"utf8")解决浏览器下载文件名中有中文时的问题
        resp.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(fileName,"utf8"));

        // 4.获取需要下载文件的流对象(输入和输出)
        FileInputStream fis = new FileInputStream(realPath);
        ServletOutputStream sos = resp.getOutputStream();

        // 将FileInputStream写入到缓冲区,再使用OutputStream将缓冲区的数据输出到浏览器
        byte[] buf = new byte[1024];
        int len;
        while((len = fis.read(buf)) != -1){
            sos.write(buf,0,len);
        }

        // 5.关闭资源
        fis.close();
        sos.close();
    }
}

web.xml:

<servlet>
    <servlet-name>fileDownload</servlet-name>
    <servlet-class>com.yang.FileDownload</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>fileDownload</servlet-name>
    <url-pattern>/dow</url-pattern>
</servlet-mapping>
响应重定向

当客户端访问一个地址时,后台可以将请求重定向到另一个资源(让客户端继续访问重定向的资源)

package com.yang;

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

public class RedirectServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 响应重定向
        //response.sendRedirect("/dow");

        // response.sendRedirect("/dow");相当于
        response.setHeader("Location","/dow"); // 跳转到/dow下
        response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); // 将状态码设置为302
    }
}

web.xml:

<servlet>
    <servlet-name>redirectServlet</servlet-name>
    <servlet-class>com.yang.RedirectServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>redirectServlet</servlet-name>
    <url-pattern>/red</url-pattern>
</servlet-mapping>

五、HttpServletRequese

  1. 获取客户端传递的参数
  2. 请求转发
获取客户端传递的参数
package com.yang.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;

public class TestRequest01 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // request对象获取单个请求参数getParameter
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        System.out.println(username);
        System.out.println(password);
        // 获取多个请求参数getParameterValues
        String[] hobbys = req.getParameterValues("hobbys");
        System.out.println(Arrays.toString(hobbys));
    }
}

web.xml:

<servlet>
    <servlet-name>request01</servlet-name>
    <servlet-class>com.yang.servlet.TestRequest01</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>request01</servlet-name>
    <url-pattern>/index</url-pattern>
</servlet-mapping>

jsp:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <%--${pageContext.request.contextPath}为当前web应用的上下文路径--%>
    <form action="${pageContext.request.contextPath}/index">
        用户名:<input type="text" name="username"><br>
        密码:<input type="password" name="password"><br>
        爱好:<input type="checkbox" name="hobbys" value="唱">唱
        <input type="checkbox" name="hobbys" value="跳">跳
        <input type="checkbox" name="hobbys" value="rap">rap
        <input type="checkbox" name="hobbys" value="篮球">篮球
        <br>
        <input type="submit" value="提交">
    </form>
</body>
</html>
请求转发

当访问servlet02:

package com.yang.servlet;

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

public class TestRequest02 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("进入到servlet02..");
        // 当客户端访问该servlet时,请求转发到servlet03
        req.getRequestDispatcher("/servlet03").forward(req,resp);
    }
}

servlet03:

package com.yang.servlet;

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

public class TestRequest03 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 向客户端响应信息
        resp.getWriter().write("servlet03...");
    }
}

web.xml:

<servlet>
    <servlet-name>servlet03</servlet-name>
    <servlet-class>com.yang.servlet.TestRequest03</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>servlet03</servlet-name>
    <url-pattern>/servlet03</url-pattern>
</servlet-mapping>

<servlet>
    <servlet-name>servlet02</servlet-name>
    <servlet-class>com.yang.servlet.TestRequest02</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>servlet02</servlet-name>
    <url-pattern>/servlet02</url-pattern>
</servlet-mapping>

响应重定向和请求转发:

  1. 当客户端访问一个servlet时,请求转发和响应重定向都可以实现页面的跳转(从该servlet中向其他servlet或者静态资源中跳转)
  2. 请求转发时,客户端的访问地址栏不会发生改变
  3. 响应重定向时,客户端的访问地址栏会变为重定向后的地址

六、Cookie

客户端第一次访问服务器时服务器创建cookie返回给客户端,然后客户端保存在本地,当发送第二次请求的时候,客户但会把上次请求的cookie数据自动的携带给服务器,服务器通过cookie就能区分不同的用户

  • 服务器响应给客户端

  • 从请求对象中获取

Cookie(String name, String value) // 创建cookie对象,是一个键值对(key-value)
Cookie[] getCookies() // 获取cookie
String getName() // 获取cookie的key
String getValue() // 获取cookie的value
void setMaxAge(int expiry) // 设置cookie的存活时间(以秒为单位),如果不设置该值,默认浏览器关闭后,cookie过期

TestCookie:

package com.yang.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;

public class TestCookie extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("UTF-8");
        resp.setCharacterEncoding("UTF-8");
        resp.setContentType("text/html");
        // 获取cookie
        Cookie[] cookies = req.getCookies();
        if (cookies != null){ // 判断客户端是否携带了cookie
            for (Cookie cookie : cookies) {
                if (cookie.getName().equals("lastLoginTime")){
                    // getValue 获取到一个String
                    // Long.parseLong将一个String转为一个long返回
                    long lastLoginTime = Long.parseLong(cookie.getValue());
                    // toLocaleString将标准时间转为年月日时分秒
                    resp.getWriter().write("上一次登录的时间:" + new Date(lastLoginTime).toLocaleString());
                }
            }
        } else {
            resp.getWriter().write("第一次访问...");
        }

        // 服务器重新访问一个cookie
        Cookie cookie = new Cookie("lastLoginTime", new Date().getTime() + "");
        // setMaxAge 设置cookie存活时间,以秒为单位
        cookie.setMaxAge(30);
        resp.addCookie(cookie);
    }
}

TestCookie02:

package com.yang.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class TestCookie02 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Cookie[] cookies = req.getCookies();
        if (cookies != null){
            for (Cookie cookie : cookies) {
                if (cookie.getName().equals("lastLoginTime")){
                    // 手动设置cookie的存活时间,将cookie的存活时间设置为0
                    cookie.setMaxAge(0);
                    resp.addCookie(cookie);
                }
            }
        }
    }
}

web.xml:

<!--设置session存活时间,单位为分-->
<session-config>
    <session-timeout>1</session-timeout>
</session-config>

<servlet>
    <servlet-name>c1</servlet-name>
    <servlet-class>com.yang.servlet.TestCookie</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>c1</servlet-name>
    <url-pattern>/c1</url-pattern>
</servlet-mapping>

<servlet>
    <servlet-name>c2</servlet-name>
    <servlet-class>com.yang.servlet.TestCookie02</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>c2</servlet-name>
    <url-pattern>/c2</url-pattern>
</servlet-mapping>

什么是会话?

客户端打开一个浏览器,访问服务器多个web资源,然后关闭浏览器,这个过程称为一次会话

七、Session(重点)

  • 客户端打开一个浏览器时,如果还没有会话,服务器会自动创建一个session对象
  • session是一个特殊的cookie(name为JSESSIONID的固定值,value为session对象的ID值)
  • 同一个客户端中不同页面的切换,存储在session中的数据不会丢失,session保存在当前会话中
  • 当该浏览器关闭后,session销毁
  • 当用户打开不同的浏览器时,会创建不同的session
  • 服务器会向客户端发送一个特有的sessionID,保存在cookie中
HttpSession getSession() // 获取session
String getId() // 获取session的id
boolean isNew() // 判断session是否为新的
ServletContext getServletContext() // 获取ServletContext对象
void setAttribute(String name, Object value) // 存放数据在session中
void removeAttribute(String name) // 根据key删除数据
void invalidate() // 销毁session,相当于关闭浏览器

TestSession:

package com.yang.servlet;

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

public class TestSession extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("UTF-8");
        resp.setContentType("text/html;charset=UTF-8");

        // 获取session
        HttpSession session = req.getSession();

        // 在session中存放数据
        session.setAttribute("name","admin");
        resp.getWriter().write("当前session的id=" + session.getId() + " 是否为新的=" + session.isNew());
    }
}

TestSession02:

package com.yang.servlet;

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

public class TestSession02 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("UTF-8");
        resp.setContentType("text/html;charset=UTF-8");

        // 获取session
        HttpSession session = req.getSession();

        // 获取存放在session中的值
        resp.getWriter().write("name=" + session.getAttribute("name"));

        // 根据key删除数据
        session.removeAttribute("name");
    }
}

TestSession03:

package com.yang.servlet;

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

public class TestSession03 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("UTF-8");
        resp.setContentType("text/html;charset=UTF-8");

        // 获取session
        HttpSession session = req.getSession();

        // 销魂当前session
        session.invalidate();
    }
}

web.xml:

<servlet>
    <servlet-name>s3</servlet-name>
    <servlet-class>com.yang.servlet.TestSession03</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>s3</servlet-name>
    <url-pattern>/s3</url-pattern>
</servlet-mapping>

<servlet>
    <servlet-name>s2</servlet-name>
    <servlet-class>com.yang.servlet.TestSession02</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>s2</servlet-name>
    <url-pattern>/s2</url-pattern>
</servlet-mapping>

<servlet>
    <servlet-name>s1</servlet-name>
    <servlet-class>com.yang.servlet.TestSession</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>s1</servlet-name>
    <url-pattern>/s1</url-pattern>
</servlet-mapping>

Cookie和Session的区别:

  • cookie保存在客户端,session保存在服务器上
  • cookie受浏览器存储量限制,session不受浏览器存储量大小限制
  • session更加安全
  • 当用户量大时,session会比较占用服务器性能

总结:

Cookie适用于存储用户的个性化设置和追踪用户行为,数据量通常较小且不涉及高敏感信息。它的优势在于能够在用户的浏览器中持久存储数据

Session适用于需要在服务器端存储用户状态和敏感数据的场景,通常用于用户身份验证和跨请求的数据管理。它的优势在于能够安全地存储较大或敏感的数据,并能在用户会话期间维持状态

八、JSP(了解)

java Servlet Pages:java服务器端页面,和Servlet一样属于动态web技术

  • JSP本质上是一个Servlet,每一个JSP继承了HttpJspBase,而HttpJspBase继承了HttpServlet
  • 当客户端访问一个JSP文件时,该JSP文件最终会被转换为一个java文件并被编译运行
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <%
        String name = "smith";
    %>
    <%=name%>
</body>
</html>

在jsp中<%%>中间可已使用java代码,<%=name%>代表将变量name的值输出到客户端

上面的jsp代码转为java代码后(部分):

out.write("\r\n");
out.write("\r\n");
out.write("<html>\r\n");
out.write("<head>\r\n");
out.write("    <title>Title</title>\r\n");
out.write("</head>\r\n");
out.write("<body>\r\n");
out.write("    ");

String name = "smith";

out.write("\r\n");
out.write("    ");
out.print(name);
out.write("\r\n");
out.write("</body>\r\n");
out.write("</html>\r\n");

在jsp中定义的变量会直接转为java代码,输出的内容会被解析为html输出到客户端

JSP基本使用

jsp表达式(<%=%>):

<%@ page import="java.util.Date" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <%--JSP表达式
        <%= 变量/表达式%> 作用:将信息输出到客户端
    --%>
    <%= new Date()%>
</body>
</html>

jsp中使用java语言(使用<%%>):

<%@ page import="java.util.Date" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <%--JSP表达式将内容输出到客户端--%>
    <%=1+2%>

    <hr>

    <%--JSP中使用java代码--%>
    <%
        class Person {
            String name;
            int age;

            public Person(String name, int age) {
                this.name = name;
                this.age = age;
            }

            @Override
            public String toString() {
                return "Person{" +
                        "name='" + name + '\'' +
                        ", age=" + age +
                        '}';
            }
        }
    %>
    <%
        Person jack = new Person("jack", 20);
        out.print(jack);
    %>

</body>
</html>

上述在jsp文件中的代码都是定义在该jsp生成的java类中的_jspService方法中

想提升变量的作用域:使用<%!%>

<%!
    static {
        System.out.println("欢迎学习JSP");
    }
    private static int age;
    public void test(){};
%>

使用<%!%>将里面的定义的java代码作用域提升到_jspService方法外

jsp中使用指令(当发生错误时,访问的资源):

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--在jsp文件中配置,当页面发生错误时,访问的页面--%>
<%@ page errorPage="/error/500.jsp" %> <%--当发生500错误时,访问静态资源500.jsp--%>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <%
        int a = 10/0;
    %>
</body>
</html>

当放生错误时,web.xml中的配置:

<!--在web.xml中配置,当发生错误时,需要跳转的页面-->
<error-page>
    <!--发生异常的状态码-->
    <error-code>404</error-code>
    <!--需要跳转的资源-->
    <location>/error/404.jsp</location>
</error-page>

页面拼接:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <%--JSP中使用页面拼接--%>
    <%--1:使用指令的形式:本质是一个页面,将多个页面的内容合为一个来展示--%>
    <%@ include file="/common/head.jsp" %>
    <h1>主体部分</h1>
    <%@ include file="/common/tail.jsp" %>

    <hr>

    <%--2:使用标签的形式:本质上是页面的拼接,多个页面显示,只是一个页面中引用了其他页面--%>
    <jsp:include page="/common/head.jsp" />
    <h1>主体部分</h1>
    <jsp:include page="/common/tail.jsp" />
</body>
</html>

使用使用指令的形式实现页面拼接时,该jsp对应的java代码(部分):

out.write("<html>\r\n");
out.write("<head>\r\n");
out.write("    <title>Title</title>\r\n");
out.write("</head>\r\n");
out.write("<body>\r\n");
out.write("    <h1>这是头部地址栏</h1>\r\n");
out.write("</body>\r\n");
out.write("</html>\r\n");
out.write("\r\n");
out.write("    <h1>主体部分</h1>\r\n");
out.write("    ");
out.write("\r\n");
out.write("\r\n");
out.write("<html>\r\n");
out.write("<head>\r\n");
out.write("    <title>Title</title>\r\n");
out.write("</head>\r\n");
out.write("<body>\r\n");
out.write("    <h1>这是底部地址栏</h1>\r\n");
out.write("</body>\r\n");
out.write("</html>\r\n");

结论:本质是一个页面,只是将多个页面的内容合为一个来展示

缺点:页面间定义的java代码会发生冲突

使用标签的形式实现页面拼接时,该jsp对应的java代码(部分):

static {
    _jspx_dependants = new java.util.HashMap<java.lang.String,java.lang.Long>(2);
    _jspx_dependants.put("/common/head.jsp", Long.valueOf(1722869144000L));
    _jspx_dependants.put("/common/tail.jsp", Long.valueOf(1722869144000L));
}
org.apache.jasper.runtime.JspRuntimeLibrary.include(request, response, "/common/head.jsp", out, false);
out.write("\r\n");
out.write("    <h1>主体部分</h1>\r\n");
out.write("    ");
org.apache.jasper.runtime.JspRuntimeLibrary.include(request, response, "/common/tail.jsp", out, false);
out.write("\r\n");

结论:本质上是页面的拼接,多个页面显示,只是一个页面中引用了其他页面

优点:页面之间定义的java代码不冲突

JSP常用内置对象
  • pageContext(代表当前页面)
  • request
  • session
  • application(servletContext)
pageContext.setAttribute("name1","jack"); // 保存的数据在当前页面中有效
request.setAttribute("name2","tom"); // 保存的数据在当前的请求中有效(请求转发后的页面可以获取)
session.setAttribute("name3","smith"); // 保存的数据在当前会话中有效
application.setAttribute("name4","milan"); // 保存的数据在当前服务器中有效

pageContext对象的setAttribute方法和findAttribute方法:

void setAttribute(String var1, Object var2) // 普通的存放数据的方法
void setAttribute(String var1, Object var2, int var3) // 可以指定该数据存放的作用域
Object findAttribute(String var1) // 从当前页面(pageContext对象)开始寻找数据,如果找不到则向上寻找(pageContext -> request -> session -> application)

九、MVC三层架构

MVC(Model View Controller)模型视图控制器

Model

  • 处理业务(Service)
  • 数据持久化(Dao)

View

  • 展示内容到客户端
  • 向服务器发送请求

Controller

  • 接收用户请求
  • 根据用户请求将需求交给业务层处理
  • 控制视图跳转

总结:客户端(View)访问访问页面时会发送请求,后端控制层(Controller)接收请求,将需求交给业务层(Model)处理,业务层通过访问数据库,将数据返回到控制层,然后控制层将数据返回到客户端

理解:顾客(View)到饭店吃饭,向服务员(控制层Controller)点餐,服务员向后厨(Service)反应,后厨做好菜交给服务员,服务员将餐交给顾客

好处:分工明确

十、Filter(重点)

  • 过滤请求
  • 处理乱码

创建一个servlet:

package com.yang.servlet;

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

public class Servlet01 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().write("使用过滤器处理乱码问题...");
    }
}

使用过滤器过滤:

package com.yang.filter;

import javax.servlet.*;
import java.io.IOException;

public class TestFilter implements Filter {
    /**
     * 伴随web服务器的启动而调用
     */
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("初始化");
    }

    /**
     * 处理需要过滤的请求,注意需要对过滤后的请求放行
     */
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("进入到过滤器...");
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");
        // 放行
        chain.doFilter(request,response);
    }

    /**
     * 伴随web服务器的关闭而调用
     */
    @Override
    public void destroy() {
        System.out.println("销毁");
    }
}

web.xml文件配置servlet和filter:

<!-- 创建同一个servlet的两个不同访问路径下用来测试过滤器 -->
<servlet>
    <servlet-name>servlet01</servlet-name>
    <servlet-class>com.yang.servlet.Servlet01</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>servlet01</servlet-name>
    <url-pattern>/servlet01</url-pattern>
</servlet-mapping>
<servlet>
    <servlet-name>servlet02</servlet-name>
    <servlet-class>com.yang.servlet.Servlet01</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>servlet02</servlet-name>
    <url-pattern>/servlet/servlet01</url-pattern>
</servlet-mapping>

<filter>
    <filter-name>filter01</filter-name>
    <filter-class>com.yang.filter.TestFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>filter01</filter-name>
    <!--处理,当访问/servlet下的任何资源时,需要经过该过滤器-->
    <url-pattern>/servlet/*</url-pattern>
</filter-mapping>

使用注解的方式配置过滤器:

@WebFilter("/*")
public class MyFilter implements Filter {
}

过滤器链:

多个过滤器可以形成过滤器链。过滤器的执行顺序由它们在web.xml中配置的顺序决定,或者按注解的加载顺序决定。

十一、实现一个简单的登录功能

登录页面Login.jsp:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>请登录</h1>
    <form action="/servlet/s1" method="post">
        <input type="text" name="username"><br>
        <input type="submit" value="登录">
    </form>
</body>
</html>

首页:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>登录成功!欢迎访问首页</h1>
    <a href="/servlet/s2">注销用户</a>
</body>
</html>

用户跨权限访问,或者用户名错误时的页面:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>用户名错误或者您无权限访问</h1>
    <a href="/Login.jsp">返回登录页面</a>
</body>
</html>

用户登录时的servlet:

package com.yang.servlet;

import com.yang.utils.UserSession;

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("/servlet/s1")
public class LoginServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        if (req.getParameter("username").equals("admin")){ // 登录成功
            req.getSession().setAttribute(UserSession.USER_SESSION,req.getSession().getId());
            resp.sendRedirect("/sys/Home.jsp");
        } else { // 登录失败
            resp.sendRedirect("/error/Error.jsp");
        }
    }
}

用户登录后注销的页面:

package com.yang.servlet;

import com.yang.utils.UserSession;

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("/servlet/s2")
public class LoginOut extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        if (req.getSession().getId() != null){
            req.getSession().removeAttribute(UserSession.USER_SESSION);
            resp.sendRedirect("/Login.jsp");
        }
    }
}

过滤器,当用户直接访问登录后才能访问的资源时,对其进行过滤:

package com.yang.filter;

import com.yang.utils.UserSession;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebFilter("/sys/*")
public class MyFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;
        if (request.getSession().getAttribute(UserSession.USER_SESSION) == null){
            req.getRequestDispatcher("/error/Error.jsp").forward(request,response);
        } else {
            chain.doFilter(req,resp);
        }
    }

    @Override
    public void destroy() {

    }
}

思路:

  1. 用户登录时,向session中存放该sessionID,作为当前用户的唯一标识
  2. 使用过滤器判断用户是否已经登录,如果已登录,则可以访问主页
  3. 用户注销后,删除session中的唯一标识该用户的属性sessionID,而不是直接删除session
  4. 跨权限访问,或者用户名错误,都让其返回登录错误页面

十二、回顾JDBC

package com.yang;

import org.junit.Test;
import java.sql.*;


public class TestJDBC {

    @Test
    public void insert() throws Exception{
        String url = "jdbc:mysql://localhost:3306/jdbc01?useUnicode=true&characterEncoding=utf8&useSSL=true";
        String username = "root";
        String password = "root";

        // 1 加载数据库驱动
        Class.forName("com.mysql.jdbc.Driver");

        // 2 获取Connection数据库对象
        Connection connection = DriverManager.getConnection(url, username, password);

        // 3 编写sql
        String sql = "insert into users values (?,?,?,?)";

        // 4 预编译
        PreparedStatement preparedStatement = connection.prepareStatement(sql);

        // 预编译
        preparedStatement.setInt(1,10);
        preparedStatement.setString(2,"张三");
        preparedStatement.setString(3,"123456");
        preparedStatement.setString(4,"男");

        // 执行sql
        int rows = preparedStatement.executeUpdate();

        System.out.println(rows > 0 ? "添加成功":"添加失败");

        // 关闭资源
        preparedStatement.close();
        connection.close();
    }

    @Test
    public void query() throws Exception{
        String url = "jdbc:mysql://localhost:3306/jdbc01?useUnicode=true&characterEncoding=utf8&useSSL=true";
        String username = "root";
        String password = "root";

        // 1 加载数据库驱动
        Class.forName("com.mysql.jdbc.Driver");

        // 2 获取Connection数据库对象
        Connection connection = DriverManager.getConnection(url, username, password);

        // 3 获取Statement对象,执行sql语句的对象
        Statement statement = connection.createStatement();

        String sql = "select * from users";

        // 4 执行sql语句
        ResultSet resultSet = statement.executeQuery(sql);

        // 遍历结果集
        while (resultSet.next()){
            System.out.println(resultSet.getObject("user_id"));
            System.out.println(resultSet.getObject("user_name"));
            System.out.println(resultSet.getObject("password"));
            System.out.println(resultSet.getObject("sex"));
        }

        // 关闭资源
        resultSet.close();
        statement.close();
        connection.close();
    }
}

JDBC事务操作:

package com.yang;

import org.junit.Test;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class TestJDBC02 {
    
    private Connection connection = null;

    /**
     * 模拟转账
     */
    @Test
    public void test(){
        String url = "jdbc:mysql://localhost:3306/jdbc01?useUnicode=true&characterEncoding=utf8&useSSL=true";
        String username = "root";
        String password = "root";
        try {
            Class.forName("com.mysql.jdbc.Driver");
            connection = DriverManager.getConnection(url, username, password);
            connection.setAutoCommit(false); // 关闭自动提交(开启事务)
            String sql01 = "update account set `money` = `money` - 100  where `name` = 'jack'";
            String sql02 = "update account set `money` = `money` + 100  where `name` = 'tom'";
            connection.prepareStatement(sql01).executeUpdate();
            connection.prepareStatement(sql02).executeUpdate();
            // int x = 1 / 0; // 制造错误,让事务回滚
            connection.commit(); // 提交事务
        } catch (Exception e) {
            try {
                // 转账发生错误,事务回滚
                connection.rollback();
            } catch (SQLException ex) {
                throw new RuntimeException(ex);
            }
            throw new RuntimeException(e);
        } finally {
            if (connection != null){
                try {
                    connection.close();
                } catch (SQLException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值