集训随笔JAVA Web

60 阅读8分钟

一.Properties类

Properties(Java.util.Properties)是Java中一个比较重要的类,主要用于读取Java的配置文件。各种语言都有自己所支持的配置文件,配置文件中很多变量是经常改变的,这样做也是为了方便用户,让用户能够脱离程序本身去修改相关的变量设置。在Java中,其配置文件常为.properties文件,格式为文本文件,文件的内容的格式是“键=值”或者“键 值”的格式,文本注释信息可以用"#"来注释。

在做Java项目开发过程中,涉及到一些数据库服务连接配置、缓存服务器连接配置等,通常情况下我们会将这些不太变动的配置信息存储在以 .properties 结尾的配置文件中。当对应的服务器地址或者账号密码信息有所变动时,我们只需要修改一下配置文件中的信息即可。

username = root
password = 123456

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    InputStream is = this.getServletContext().getResourceAsStream("/WEB-INF/classes/db.properties");

    Properties prop = new Properties();
    prop.load(is);
    String username = prop.getProperty("username");
    String password = prop.getProperty("password");

    resp.getWriter().print(username+","+password);


}

二. StringBuffer

StringBuffer是String的增强类

类似一个字符串数组,可用方法添加,删除,替换,插入

  1. 添加

    StringBuffer string = new StringBuffer("hello,")
    string.append("world")
    //输出为  hello,world
    //添加多个可以直接 append.append.append
    string.append("good").append("true")
    //输出  hello,worldgoodtrue
    
  2. 删除

    string.delete(1,4)
    //输出为 ho,worldgoodtrue    
    
  3. 替换

    // 遵循左闭右开原则
    string.replace(0,3,"java")
    //输出结果  javaworldgoodtrue
    
  4. 插入

    string.inert(0,"hello")
    //结果为hellojavaworldgoodtrue
    

在javaweb中实现验证码时出现的案例

private String makeNum(){
    Random random = new Random();
    String num =  random.nextInt(9999999)+"";
    StringBuffer sb = new StringBuffer();
    for (int i =0;i<7-num.length();i++){
        sb.append("0");
    }
    num = sb.toString() + num;
    return num;
}

这里可以确保出现的数字为七位数,不足的会面用零填充

三. 实现前后端交互时遇到的问题

form表单中method的属性

Form提供了两种数据传输的方式——get和post。虽然它们都是数据的提交方式,但是在实际传输时确有很大的不同,并且可能会对数据产生严重的影响。虽然为了方便的得到变量值,Web容器已经屏蔽了二者的一些差异,但是了解二者的差异在以后的编程也会很有帮助的。

Form中的get和post方法,在数据传输过程中分别对应了HTTP协议中的GET和POST方法。二者主要区别如下:
1、Get是用来从服务器上获得数据,而Post是用来向服务器上传递数据。
2、Get将表单中数据的按照variable=value的形式,添加到action所指向的URL后面,并且两者使用“?”连接,而各个变量之间使用“&”连接;Post是将表单中的数据放在form的数据体中,按照变量和值相对应的方式,传递到action所指向URL。
3、Get是不安全的,因为在传输过程,数据被放在请求的URL中,而如今现有的很多服务器、代理服务器或者用户代理都会将请求URL记录到日志文件中,然后放在某个地方,这样就可能会有一些隐私的信息被第三方看到。另外,用户也可以在浏览器上直接看到提交的数据,一些系统内部消息将会一同显示在用户面前。Post的所有操作对用户来说都是不可见的。
4、Get传输的数据量小,这主要是因为受URL长度限制;而Post可以传输大量的数据,所以在上传文件只能使用Post(当然还有一个原因,将在后面的提到)。
5、Get限制Form表单的数据集的值必须为ASCII字符;而Post支持整个ISO10646字符集。
6、Get是Form的默认方法。
使用Post传输的数据,可以通过设置编码的方式正确转化中文;而Get传输的数据却没有变化。

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h1>登录</h1>
<div>
    <form action="${pageContext.request.contextPath}/get" method="post">
        用户名:<input type="text" name="username"><br>
        密码:<input type="password" name="password"><br>
        爱好:
            <input type="checkbox" name="happy" value="女孩">女孩
            <input type="checkbox" name="happy" value="音乐">音乐
            <input type="checkbox" name="happy" value="电影">电影
            <input type="checkbox" name="happy" value="运动">运动
        <br>
        <input type="submit" value="登录">
    </form>
</div>
</body>
</html>

关于${pageContext.request.contextPath}的理解

${pageContext.request.contextPath}是JSP取得绝对路径的方法,等价于<%=request.getContextPath()%> 。也就是取出部署的应用程序名或者是当前的项目名称 比如我的项目名称是demo1在浏览器中输入http://localhost:8080/demo1/a.jsp "${pageContext.request.contextPath}或 <%=request.getContextPath()%>" 取出来的就是 /demo1,而"/"代表的含义就是http://localhost:8080 故有时候项目中这样写 ${pageContext.request.contextPath}/a.jsp

四.setCharacterEncoding和setContentType的理解

从服务器端角度看,两个方法就是给服务器返回前端的内容进行编码设置。

但是内容是要在平台上展示的,而平台也是有自己的charset的。如果平台用来展示内容的charset与内容不符合时,出现的依然是乱码。

setCharacterEncoding

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    resp.setCharacterEncoding("utf-8");
    PrintWriter writer = resp.getWriter();

    writer.print("AC米兰足球队");
    writer.close;
}

但得到的页面是

image.png

这是由于setCharacterEncoding只是设置字符的编码方式,所以浏览器收到了正经UTF8编码的内容,但是浏览器并没有得到任何提示或者要求用什么编码方式来呈现这段内容!所以浏览器使用的是默认编码方式。GBK

通过修改

setContentType

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//        resp.setCharacterEncoding("utf-8");
        resp.setContentType("text/html;charset=utf-8");
        PrintWriter writer = resp.getWriter();

        writer.print("AC米兰足球队");
        writer.close();
    }

image.png

这是由于setContentType除了可以设置字符的编码方式还能设置文档内容的类型,用标准的MIME格式设置了服务器响应内容的字符集是UTF8,并且添加了响应头,告诉浏览器该使用什么编码集来显示内容:

两者也可以同时使用

public class cookie extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setCharacterEncoding("utf-8");
        resp.setContentType("text/html");
        PrintWriter writer = resp.getWriter();

        writer.print("AC米兰足球队");
        writer.close();
    }

setContentType提供的MIME只有类型没有编码方案,此时setCharacterEncoding的内容就称为了contentType中charset的内容。

五.JSP详解

JSP页面本质上是一个Servlet程序,第一次访问JSP页面时(运行Tomcat服务器后在浏览器地址栏输入路径),Tomcat服务器会将此JSP页面翻译成为一个Java源文件,并对其进行编译成为.class字节码文件(一个.java,一个.class),

常见脚本

1.声明脚本

  • 格式:<%! 声明Java代码 %>
  • 作用:可以给JSP翻译出来的Java类定义属性、方法、静态代码块、内部类等
  • 特点:不会在浏览器的页面上显示出来,仅存在于翻译后的Java类中
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="java.util.HashMap" %>
<%@ page import="java.util.Map" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <%--1.声明类属性--%>
    <%!
        private String name;
        private static Map<String, Object> map;
    %>
    <%--2.声明类方法--%>
    <%!
        public int sum() {
            return 12;
        }
    %>
    <%--3.声明静态代码块--%>
    <%!
        static {
            map = new HashMap<String, Object>();
            map.put("key1", "value1");
        }
    %>
</body>
</html>

2.表达式脚本

  • 格式:<%=表达式 %>
  • 作用:在浏览器的JSP页面上输出数据(只有此脚本可以在浏览器的页面上输出数据)
  • 特点:
    • (1) 所有的表达式脚本都会被翻译到对应的Java类的_jspService()方法中,故表达式脚本可以 直接使用_jspService()方法参数中的对象
    • (2) 表达式脚本都会被编译后的Java类中的out.print()方法输出到浏览器页面上
    • (3) 表达式脚本中的表达式不能以分号结束
<%=22 %> <br/>
<%="可以输出字符串" %> <br/>
<%=map %> <br/>
<%--使用_jspService方法中的对象--%>
<%=request.getParameter("username") %>

3.代码脚本

  • 格式:<% Java语句 %>
  • 作用:在JSP页面中可以编写需要的Java代码
  • 特点:
    • (1) 代码脚本翻译后都在_jspService方法中,故代码脚本可以直接使用此方法参数中的对象
    • (2) 可以由多个代码脚本块组合完成一个完整的Java语句
    • (3) 代码脚本还可以和表达式脚本一起组合使用,在JSP页面上输出数据
<%--1.if语句--%>
<%
    int i = 1;
    if (i == 1) {
        System.out.println("我爱祖国!");
    } else {
        System.out.println("我很爱祖国!");
    }
%> <br/>
<%--2.for循环语句--%>
<%
    for (int j = 0 ; j < 3; j++) {
        System.out.println("第" + j + "次循环");
    }
%> <br/>
<%--3.使用_jspService方法参数中的对象--%>
<%
    String username = request.getParameter("username");
    System.out.println("username对应的值为:" + username);
%>

4.九大内置对象

  • request:请求对象
  • response:响应对象
  • pageContext:JSP的上下文对象
  • session:会话对象
  • application:ServletContext对象
  • config:ServletConfig对象
  • out:JSP输出流对象
  • page:指向当前JSP的对象
  • exception:异常对象

5.四大域对象

image.png 域对象是指可以像Map一样存取数据的对象,四个域对象功能一样,只是对数据的存取范围不同

6.常用的JSP标签

image.png

7.JSTL

JSTL(Java server pages standarded tag library),即JSP标准标签库是由JCP所制定的标准规范,它主要提供给Java Web开发人员一个标准通用的标签库,并由Apache的Jakarta小组来维护。开发人员可以利用这些标签取代JSP页面上的Java代码,从而提高程序的可读性,降低程序的维护难度。

image.png

最常用的两个方法

Core标签库:Core支持JSP中的一些基本的操作;

  • 表达式控制标签:out、set、remove、catch
  • 流程控制标签:if、choose、when、otherwise
  • 循环标签:forEach、forTokens
  • URL操作

注意: 使用标签时,一定要在jsp文件头加入以下代码:

<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

1、<c:out>

  • 用来显示数据对象(字符串、表达式)的内容或结果,输出值
  • 使用Java脚本的方式为:<% out.println("hello") %>  <% =表达式 %>
  • 使用JSTL标签:<c:out value="字符串">,

<c:out>标签用于在JSP中显示数据,它有如下属性:

image.png

<form action="coreif.jsp" method="get">
<%--
  EL表达式获取表单中的信息
  ${param.参数名}
  --%>
    <input type="text" name="username" value="${param.username}">
    <input type="submit" value="登录">

<c:out value=”${user.username}” default=”guest”/>
</form>

显示用户的用户名,如为空则显示guest

2、<c:set>

用于将变量存取于 JSP 范围中或 JavaBean 属性中。

<c:set>标签用于保存数据,它有如下属性: image.png

<c:set value="${test.testinfo}" var="test2" scope=”session” />

将test.testinfo的值保存到session的test2中,其中test是一个javabean的实例,testinfo是test对象的属性。

六.过滤器

过滤器原理

当我们使用过滤器时,过滤器会对游览器的请求进行过滤,过滤器可以动态的分为3个部分,

  1. 放行之前的代码
  2. 放行
  3. 放行后的代码,这3个部分分别会发挥不同作用。
    • 第一部分代码会对浏览器请求进行第一次过滤,然后继续执行
    • 第二部分代码就是将浏览器请求放行,如果还有过滤器,那么就继续交给下一个过滤器
    • 第三部分代码就是对返回的Web资源再次进行过滤处理

我们使用过滤器,也就是说,不止请求会经过过滤器,我们的响应也会经过过滤器。

过滤器的三个接口

构建过滤器需要连接Filter接口

public class filter implements Filter 

并且导入三个包 image.png

使用过滤器

public class lister implements Filter {
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("Filter初始化");
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
        resp.setContentType("text/html;charset=utf-8");

        System.out.println("Filter执行前...");
        chain.doFilter(req,resp);// 作用是让我们的程序继续走,如果不写,程序到这里就被拦截停止!
        System.out.println("Filter执行后...");
    }

    public void destroy() {
        System.out.println("Filter销毁");
    }
}

在xml中配置

<filter>
    <filter-name>writer</filter-name>
    <filter-class>filer.lister</filter-class>
</filter>
<filter-mapping>
    <filter-name>writer</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

FilterConfig

类图以及源代码 image.png

image.png

里面的方法就4个,下面我们分别进行讲解

  • getFilterName():获取filter的名称
  • getServletContext():获取ServletContext
  • getInitparamter(String var1):获取配置的初始参数的值
  • getInitParamterNames():获取配置的所有参数名称
@Override
public void init(FilterConfig filterConfig) throws ServletException {
    System.out.println("-------------获取全部的key:value-------------");
    // 获取所有的配置参数的名字
    Enumeration<String> names = filterConfig.getInitParameterNames();

    while (names.hasMoreElements()){
        // 得到每一个名字
        String name = names.nextElement();
        System.out.println(name+"="+filterConfig.getInitParameter(name));
    }

    System.out.println("----------------end------------------");
}
<filter>
    <filter-name>writer</filter-name>
    <filter-class>filer.lister</filter-class>

    <init-param>
        <param-name>diver</param-name>
        <param-value>com.mysql.jdbc.Driver</param-value>
    </init-param>

    <init-param>
        <param-name>username</param-name>
        <param-value>root</param-value>
    </init-param>

    <init-param>
        <param-name>password</param-name>
        <param-value>root</param-value>
    </init-param>
</filter>

image.png

FilterChain

类图以及源代码 image.png

image.png

我们查看类图,可以发现FilterChain就只有一个方法,其实这个方法就是用来对拦截进行放行的,如果有多个拦截器,那么就会继续调用下一个Filter进行拦截。doFilter方法需要传入个参数,一个是ServletRequest,一个是ServletResponse参数,这个直接传入进行。

Tomcat在调用过滤器时,默认就会传入Request和Response,这个参数封装了请求和响应,我们直接使用就行。ServletResquest和ServletResponse可以直接强转成HttpServletRequest和HttpServletResponse,然后使用相应的方法。

@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
    resp.setContentType("text/html;charset=utf-8");

    System.out.println("Filter执行前...");
    chain.doFilter(req,resp);// 作用是让我们的程序继续走,如果不写,程序到这里就被拦截停止!
    System.out.println("Filter执行后...");
}

image.png

七.监听器

1.概念

在JavaWeb应用程序中,Listener(监听器) 是一种机制,用于监听和响应特定的事件。它可以感知并响应与应用程序相关的事件,从而执行相应的逻辑处理。

2.Listener的生命周期

监听器(Listener)在JavaWeb应用程序中起到监听和处理事件的作用。监听器的生命周期与Web应用程序的生命周期密切相关。

  1. ServletContextListener:ServletContextListener会在Web应用程序启动时起作用,并在Web应用程序关闭时销毁.具体来说,当Web容器启动时会触发contextInitialized()方法,开发者可以在这个方法中进行一些初始化操作;当Web容器关闭时会触发contextDestroyed()方法,开发者可以在这个方法中进行一些资源释放、清理操作。

  2. ServletRequestListener:ServletRequestListener会在每次客户端请求到达服务器时起作用,并在服务器响应完成后销毁。具体来说,当客户端发送请求到达服务器时会触发requestInitialized()方法,开发者可以在这个方法中获取和处理请求相关的信息;当服务器响应完成后会触发requestDestroyed()方法,开发者可以在这个方法中进行一些善后操作。

  3. HttpSessionListener:HttpSessionListener会在每次HttpSession创建和销毁时起作用。具体来说,当用户访问Web应用程序时,如果尚未创建HttpSession,会触发sessionCreated()方法,在这个方法中可以进行一些会话管理的操作;当HttpSession被销毁时,会触发sessionDestroyed()方法,在这个方法中可以进行一些会话清理的操作。

注意,监听器是通过在web.xml配置文件中声明来启用的。开发者需要在web.xml文件中添加相应的监听器声明,告诉Web容器要监听哪些事件,并指定相应的监听器类。

总之,监听器的起作用和销毁是在Web应用程序的生命周期中发生的,监听器会在特定的事件发生时被触发,并执行相应的回调方法来处理事件。

举例

package lister;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

public class listener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        System.out.println("应用程序已启动");
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        System.out.println("应用程序已关闭");
    }
}
<listener>
    <listener-class>lister.listener</listener-class>
</listener>