JAVAWEB基础知识

简介

本章不涉及安全部份,为学习javaweb安全的必备基础,为以后学习铺垫。

资源&书签索引

java代码审之路https://www.cnblogs.com/afanti/p/13156152.html

靶场https://github.com/JoyChou93/java-sec-code 

java反射机制详解

网课笔记

课程:https://www.imooc.com/learn/199

(老师的声音有点像蕾丝

Class类

class类是java.lang中的类,java中的class类只能由JVM访问。

任何一个类都是Class类的实例对象,这个实例对象有三种表达方式

我们也可以通过类的类型来实例化这个类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package com.day1;

public class ReflectDemo1 {
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
Foo foo1 = new Foo();
Class c1 = Foo.class;
Class c2 = foo1.getClass();

/*c1,c2表示Foo类的Class type*/
// System.out.println(c1==c2);//true

Class c3 = null;
try {
c3 = Class.forName("com.day1.Foo");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
System.out.println(c3==c2);//true

/*
* 可以通过该类的类型来创建这个类的对象实例
* 但是要进行强制类型转换
*
*/

Foo foo = (Foo) c3.newInstance();
foo.print();


}
}
class Foo{
void print(){
System.out.println("Foo print");
}
}

Java动态加载类

Class.forName()表示了动态加载类,表示动态编译。

编译时加载类是静态加载类

运行时加载类是动态加载类

获取方法信息

基本的数据类型也存在对应的类类型

编写一个工具类进行练习,存在一个打印传入类信息的方法,使用反射实现

方法信息被封装在java.lang.reflect.Method中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package com.day1;

import java.lang.reflect.Method;

public class ClassUtil {
//打印类的信息
public static void printClassMessage(Object obj){
//获取类类型
Class c = obj.getClass();
//获取类的名称
System.out.println("该类的名称是==>"+c.getName());
//获取类的方法信息
/*
* Method类,方法对象
* 一个成员方法就是一个Method对象
* getMethods()方法获取的是所有public函数,包括从父类继承来的
* */
Method[] methods = c.getMethods();
for (int i = 0; i < methods.length; i++) {
//得到方法返回值类型
Class<?> returnType = methods[i].getReturnType();
System.out.print(returnType.getName()+" ");
//方法名
System.out.print(methods[i].getName()+"(");
//参数类型
Class<?>[] parameterTypes = methods[i].getParameterTypes();
for (Class class1 : parameterTypes){
System.out.print(class1.getName()+",");
}
System.out.println(")");
}
}
}

获取其他的信息

我们可以通过类类型(Class Type)来获取方法信息,也就说明我们可以通过它获取别的信息

例如成员变量信息,它被封装在java.lang.reflect.Field中

构造函数信息,它被封装在java.lang.reflect.Constructor中

我们可以通过对象来获取到类的其他信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/**
* 输出类的Field信息
* @param obj
*/
public static void printFieldMessage(Object obj) {
Class<?> c = obj.getClass();
//Field[] fs = c.getFields();
Field[] fs = c.getDeclaredFields();//获取声明了的成员变量的信息
for (Field field : fs) {
//得到成员变量的类类型
Class fieldType = field.getClass();
String typeName = fieldType.getName();
String fieldName = field.getName();
System.out.println("typename:" + typeName + " fieldName:" + fieldName);
}
}

/**
* 输出类的构造函数的信息
* 构造函数
* @param obj
*/
public static void printConMessage(Object obj){
Class<?> c = obj.getClass();
Constructor[] constructors = c.getDeclaredConstructors();
for (Constructor constructor1: constructors
) {
String constructor1Name = constructor1.getName();
System.out.print(constructor1Name+"(");
//获取构造函数的参数列表
Class[] parameterTypes = constructor1.getParameterTypes();
for (Class class1:parameterTypes
) {
System.out.print(class1.getName()+",");
}
System.out.println(")");
}
}

方法反射的基本操作

  • 如何获取某个方法

    方法的名称和方法的参数列表,才能唯一决定某个方法

  • 如何方法反射的操作

    method.invoke(对象,参数列表)

TestMehod类:

1
2
3
4
5
6
7
8
9
class TestMehod {
public void print(int a,int b){
System.out.println(a+b);
}

public void print(String a,String b){
System.out.println(a.toUpperCase()+b);
}
}

获取一个方法,首先要获取类的信息

获取类的信息先要获取类的参数列表

1
2
3
TestMehod test = new TestMehod();
Class aClass = test.getClass();
//获取到TestMehod类的信息

获取方法,要求方法名和参数列表

getMethod获取到public的方法,getDeclaredMethod获取到声明了的方法

1
2
3
/        aClass.getMethod("print", int.class, int.class)
// aClass.getMethod("print",new Class[]{int.class,int.class});
Method m = aClass.getDeclaredMethod("print", int.class, int.class);

然后通过获取到的方法,来进行方法调用

也就是方法的反射操作,反过来通过操作test对象来调用方法

1
2
3
//            Object o = m.invoke(test, new Object[]{1, 2});
Object o2 = m.invoke(test, 1, 2);
//等效于test.print()

同样:

等价于test.print(“hello”,”WORLD”);

1
2
3
4
//通过String.class来获取到想要的另一个方法类型
Method m2 = aClass.getMethod("print", String.class, String.class);
//通过方法来反射操作
Object o2 = m2.invoke(test, "hello", "WORLD");

如果想要获取的方法没有参数可以这样写

1
2
Method m3 = aClass.getMethod("print",new Class[]{});
Method m3 = aClass.getMethod("print");

通过反射来了解泛型的本质

通过Class,Method来了解泛型的本质

之前我们使用集合:

1
2
3
//集合操作
ArrayList list = new ArrayList();//任何类型
ArrayList<String> list1 = new ArrayList<>();//只能放String类型

其实,之前所说的类类型,也可以叫做字节码

因为反射的操作都是编译之后的操作

1
2
3
Class c1 = list.getClass();
Class c2 = list1.getClass();
System.out.println(c1==c2);//true,说明编译之后集合是去泛型化的

所以java中,集合的泛型是防止错误输入的,只在编译阶段有效

编译之后泛型就无效了

我们可以通过方法的反射来操作,绕过泛型的限制

1
2
3
4
        Method add = c1.getMethod("add", Object.class);
add.invoke(list1,100);
//原先是加不进去的
System.out.println(list1.toString());

反射的操作,一系列操作都是绕过编译,在运行时刻执行的。

什么是反射

(1)Java反射机制的核心是在程序运行时动态加载类并获取类的详细信息(此时已经编译后),从而操作类或对象的属性和方法。本质是JVM得到class对象之后,再通过class对象进行反编译,从而获取对象的各种信息。

(2)Java属于先编译再运行的语言,程序中对象的类型在编译期就确定下来了,而当程序在运行时可能需要动态加载某些类,这些类因为之前用不到,所以没有被加载到JVM。通过反射,可以在运行时动态地创建对象并调用其属性,不需要提前在编译期知道运行的对象是谁。

反射的原理

下图是类的正常加载过程、反射原理与class对象:

Class对象的由来是将**.class文件读入内存,并为之创建一个Class对象。**

image-20220301223149-1sjhfyl.png

反射的优缺点

1、优点:在运行时获得类的各种内容,进行反编译,对于Java这种先编译再运行的语言,能够让我们很方便的创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代码的链接,更加容易实现面向对象。

2、缺点:

(1)反射会消耗一定的系统资源,因此,如果不需要动态地创建一个对象,那么就不需要用反射;

(2)反射调用方法时可以忽略权限检查,因此可能会破坏封装性而导致安全问题。

反射的用途

1、反编译:.class–>.java

2、通过反射机制访问java对象的属性,方法,构造方法等

3、当我们在使用IDE,比如Ecplise时,当我们输入一个对象或者类,并想调用他的属性和方法是,一按点号,编译器就会自动列出他的属性或者方法,这里就是用到反射。

4、反射最重要的用途就是开发各种通用框架。比如很多框架(Spring)都是配置化的(比如通过XML文件配置Bean),为了保证框架的通用性,他们可能需要根据配置文件加载不同的类或者对象,调用不同的方法,这个时候就必须使用到反射了,运行时动态加载需要的加载的对象。

5、例如,在使用Strut2框架的开发过程中,我们一般会在struts.xml里去配置Action,比如

1
2
3
4
<action name="login" class="org.ScZyhSoft.test.action.SimpleLoginAction" method="execute">   
<result>/shop/shop-index.jsp</result>
<result name="error">login.jsp</result>
</action>

比如我们请求login.action时,那么StrutsPrepareAndExecuteFilter就会去解析struts.xml文件,从action中查找出name为login的Action,并根据class属性创建SimpleLoginAction实例,并用Invoke方法来调用execute方法,这个过程离不开反射。配置文件与Action建立了一种映射关系,当View层发出请求时,请求会被StrutsPrepareAndExecuteFilter拦截,然后StrutsPrepareAndExecuteFilter会去动态地创建Action实例。

比如,加载数据库驱动的,用到的也是反射。

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

反射机制常用的类

Java.lang.Class;

Java.lang.reflect.Constructor;

Java.lang.reflect.Field;

Java.lang.reflect.Method;

Java.lang.reflect.Modifier;

Tomcat

tomcat目录结构:https://www.jianshu.com/p/81ec9c51435e

tomcat配置文件详解:https://www.cnblogs.com/54chensongxia/p/13255055.html

tomcat目录结构及配置文件:https://blog.51cto.com/botao/72331

Maven

在javaweb开发中,需要使用大量的jar包,这些jar包需要我们手动导入,一般在lib文件夹下,

Maven是一个架构管理工具

Maven的核心思想:约定大于配置

配置环境变量,换源

1
2
3
4
5
6
<mirror>
<id>nexus-aliyun</id>
<mirrorOf>central</mirrorOf>
<name>Nexus aliyun</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>

建立一个本地仓库

1
<localRepository>C:\JAVA\apache-maven-3.8.4\maven-repo</localRepository>

在idea中配置maven

image-20220302113634-tlpkydk.png

image-20220302114323-7karkv2.png

idea项目创建成功之后,看一眼配置,确认maven配置在自己本地的目录下面

配置tomcat解释器

image-20220302115549-w2fq3xv.png

虚拟路径映射

image-20220302120012-4zrxqrw.png

pom.xml

maven之pom.xml配置文件详解https://www.jianshu.com/p/0e3a1f9c9ce7

远程仓库

https://mvnrepository.com/

Servlet

第一个Servlet

servlet是sun公司开发动态web的一门技术

  • 编写一个类,实现servlet接口
  • 把开发好的Java类部署到web服务器中

添加依赖

HelloServlet

创建一个普通的Maven项目,删掉里面的src目录,之后直接建立模块,这个空工程就是Maven主工程

关于Maven父子工程的理解

maven环境优化

1.修改web.xml为最新的

2.将maven结构完整

image-20220302142601-vx3r0vj.png

编写一个Servlet程序

  • 编写一个普通类
  • 实现Servlet接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {


// ServletOutputStream outputStream = resp.getOutputStream();
PrintWriter writer = resp.getWriter();//响应流
writer.print("Hello Servlet");

}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doGet(req, resp);
}
}

编写Servlet的映射

我们写的是java程序,但是需要通过浏览器访问,而浏览器需要连接web服务器,所以我们要在web服务中注册我们写的Servlet

还要给他一个浏览器能够访问的路径

注册Servlet:

src/main/webapp/WEB-INF/web.xml

1
2
3
4
5
6
7
8
9
10
<!--注册Servlet -->
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.kuang.servlet.HelloServlet</servlet-class>
</servlet>
<!--Servlet的请求路径-->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>

配置Tomcat

image-20220302172025-ari1pa8.png

发布路径

image-20220302171335-7b2r7uj.png

编译之后发布的网站目录

image-20220302172225-s7miesw.png

image-20220302172528-yx480ef.png

Servlet原理

Servlet体系结构

image-20220302174114-1z0k2mo.png

Servlet的框架是由两个Java包组成的:javax.servlet与javax.servlet.http。

在javax.servlet包中定义了所有的Servlet类都必须实现或者扩展的通用接口和类。

在javax.servlet.http包中定义了采用Http协议通信的HttpServlet类。

Servlet的框架的核心是javax.servlet.Servlet接口,所有的Servlet都必须实现这个接口。

image-20220302174428-d0konpg.png

1
2
3
4
5
1. init(ServletConfig)方法:负责初始化Servlet对象,在Servlet的生命周期中,该方法执行一次;该方法执行在单线程的环境下,因此开发者不用考虑线程安全的问题;
2. service(ServletRequest req,ServletResponse res)方法:负责响应客户的请求;为了提高效率,Servlet规范要求一个Servlet实例必须能够同时服务于多个客户端请求,即service()方法运行在多线程的环境下,Servlet开发者必须保证该方法的线程安全性;
3. destroy()方法:当Servlet对象退出生命周期时,负责释放占用的资源;
4. getServletInfo:就是字面意思,返回Servlet的描述;
5. getServletConfig:这个方法返回由Servlet容器传给init方法的ServletConfig。

ServletRequest & ServletResponse

对于每一个HTTP请求,servlet容器会创建一个封装了HTTP请求的ServletRequest实例传递给servlet的service方法,ServletResponse则表示一个Servlet响应,其隐藏了将响应发给浏览器的复杂性。通过ServletRequest的方法你可以获取一些请求相关的参数,而ServletResponse则可以将设置一些返回参数信息,并且设置返回内容。

Servlet工作原理

当Web服务器接收到一个HTTP请求时,它会先判断请求内容:

如果是静态网页数据,Web服务器将会自行处理,然后产生响应信息;

如果牵涉到动态数据,Web服务器会将请求转交给Servlet容器。此时Servlet容器会找到对应的处理该请求的Servlet实例来处理,结果会送回Web服务器,再由Web服务器传回用户端。

image-20220302193609-s6ivgis.png

接着我们描述一下Tomcat与Servlet是如何工作的,首先看下面的时序图:

image-20220302193656-6lc2zmi.png

  • Web Client 向Servlet容器(Tomcat)发出Http请求;
  • Servlet容器接收Web Client的请求;
  • Servlet容器创建一个HttpRequest对象,将Web Client请求的信息封装到这个对象中;
  • Servlet容器创建一个HttpResponse对象;
  • Servlet容器调用HttpServlet对象的service方法,把HttpRequest对象与HttpResponse对象作为参数传给 HttpServlet对象;
  • HttpServlet调用HttpRequest对象的有关方法,获取Http请求信息;
  • HttpServlet调用HttpResponse对象的有关方法,生成响应数据;
  • Servlet容器把HttpServlet的响应结果传给Web Client;

Servlet生命周期

在Servlet接口中定义了5个方法,其中3个方法代表了Servlet的生命周期:

1
2
3
1. init(ServletConfig)方法:负责初始化Servlet对象,在Servlet的生命周期中,该方法执行一次;该方法执行在单线程的环境下,因此开发者不用考虑线程安全的问题;
2. service(ServletRequest req,ServletResponse res)方法:负责响应客户的请求;为了提高效率,Servlet规范要求一个Servlet实例必须能够同时服务于多个客户端请求,即service()方法运行在多线程的环境下,Servlet开发者必须保证该方法的线程安全性;
3. destroy()方法:当Servlet对象退出生命周期时,负责释放占用的资源;

image-20220302194002-fsajmvr.png

servlet-mapping的配置与问题

https://blog.csdn.net/qfikh/article/details/52565976

Servlet的详细使用

ServletContext

https://blog.csdn.net/gavin_john/article/details/51399425

web容器在启动的时候,他会为每个web程序都创建一个对应的ServletContext对象,它代表了当前的web应用

image-20220302223905-rkr4zwl.png

  • 共享数据
  • 获取初始化参数 context.getInitParameter()
  • 请求转发 context.getRequestDispatcher()
  • 读取资源文件

编写一个ServletContext

需要一个放置数据的类,需要一个读取的类,然后配置web.xml

编写一个Servlet,获取到ServletContext类,往里面加入一个属性

1
2
3
4
5
6
7
8
9
10
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = this.getServletContext();

String username = "admin";//数据k
context.setAttribute("username",username);//将一个数据保存在了ServletContext中,名字为username,值username

}
}

写另一个类,在其中获取到和上面一样的ServletContext类,在里面取出属性并打印到页面中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class GetServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = this.getServletContext();
String username = (String) context.getAttribute("username");

resp.getWriter().println("username:"+username);

}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doGet(req, resp);
}
}

写完之后注册路由

image-20220302225223-a5nhirq.png

读取资源文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class PropertiesServlet extends HttpServlet {
@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 user = prop.getProperty("username");
String pwd = prop.getProperty("password");

resp.getWriter().println("user:"+user+" pwd:"+pwd);
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doGet(req, resp);
}
}

HttpServletResponse

web服务器接收到客户端的http请求,会针对这个请求,分别创建一个代表请求的HttpServletRequest对象,代表响应的一个HttpServletResponse

  • 如果要获取客户端请求过来的参数:找HttpServletRequest
  • 如果要给客户端响应一些个信息,找HttpServletResponse

https://www.cnblogs.com/xdp-gacl/p/3798347.html

常见应用:

  • 向浏览器输出消息

  • 下载文件:

    • 要获取下载文件的路径
    • 下载的文件名字是什么
    • 设置想办法让浏览器能支持我们下载的东西
    • 获取下载文件的输入流
    • 创建缓冲区
    • 获取OutPutStream对象
    • 将FileOutPutStream写入到缓冲区Buffer
    • 将Buffer中的数据输出到客户端

下载文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package com.kuang.servlet;

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;

public class FileServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String realPath = "C:\\Users\\Liyc\\IdeaProjects\\javaweb-1-study\\servlet-03\\target\\classes\\1.jpg";
System.out.println("Download path: "+realPath);

//获取下载的文件名
String fileName = realPath.substring(realPath.lastIndexOf("\\") + 1);

//设置浏览器行为
resp.setHeader("Content-disposition","attachment;filename="+fileName);
//获取下载文件的输入流
FileInputStream in = new FileInputStream(realPath);
//创建缓冲区
int len = 0;
byte[] buffer = new byte[1024];
//获取到输出流对象
ServletOutputStream out = resp.getOutputStream();
//将文件输入流写入到buffer缓冲区,使用OutputStream输出到客户端
while((len=in.read(buffer))>0) {
out.write(buffer,0,len);
}
in.close();
out.close();
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doGet(req, resp);
}
}

实现后端验证码

需要用到java的图片类,生成一个图片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
package com.kuang.servlet;

import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;

public class ImageServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//让浏览器五秒刷新一次
resp.setHeader("refresh","5");

//在内存中生成一个图片
BufferedImage bufferedImage = new BufferedImage(200,40,BufferedImage.TYPE_INT_RGB);
//得到图片
Graphics2D graphics = (Graphics2D) bufferedImage.getGraphics();//画笔
graphics.setColor(Color.MAGENTA);
graphics.fillRect(0,0,200,40);
//给图片写数据
graphics.setColor(Color.BLUE);
graphics.setFont(new Font(null,Font.BOLD,20));
graphics.drawString(makeNum(),100,20);

//告诉浏览器这个请求用图片的方式打开
resp.setContentType("image/jpeg");
resp.setDateHeader("expires",-1);//缓存控制
resp.setHeader("Cache-Control","no-cache");
resp.setHeader("Pragma","no-cache");

//把图片写道浏览器
ImageIO.write(bufferedImage,"jpg",resp.getOutputStream());
}

//生成随机数
private String makeNum(){
Random random = new Random();
String num = random.nextInt(9999) + "";
StringBuffer sb = new StringBuffer();
for (int i = 0; i < 4-num.length(); i++) {
sb.append("0");
}
return sb.toString() + num;

}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doGet(req, resp);
}
}

33bba4a6ee5f567669c78bcee74b9a6-20220303002134-xeyc728.png

实现重定向(*)

1
resp.sendRedirect("/s3/image");

HttpServletRequest

处理客户端发来的http请求并处理

1.获取前端传递的参数

index.jsp

以post的方式提交表单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登录</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/login" method="POST">
<h1>Login</h1>
<input type="text" name="username" placeholder="Username">
<input type="password" name="password" placeholder="password">
<input type="checkbox" name="hobbies" value="Video game">
<input type="checkbox" name="hobbies" value="Animation">
<input type="checkbox" name="hobbies" value="Football">
<input type="submit" name="" value="Login">
</form>
</body>

</html>

写一个Servlet来获取参数和请求转发

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
String username = req.getParameter("username");
String password = req.getParameter("password");
String[] hobbies = req.getParameterValues("hobbies");

System.out.println(username);
System.out.println(password);
System.out.println(Arrays.toString(hobbies));

//通过请求转发
req.getRequestDispatcher("/success.jsp").forward(req,resp);
}
}

2.请求转发

实现Cookie

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class CookieDemo extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
resp.setCharacterEncoding("UTF-8");

PrintWriter out = resp.getWriter();

//Cookie 服务端到客户端获取
Cookie[] cookies = req.getCookies();

if (cookies!=null){
out.write("你上一次访问的时间是:");
for (Cookie cookie:cookies
) {
if(cookie.getName().equals("loginTime")){
//获取cookie中的值
String value = cookie.getValue();
long time = Long.parseLong(value);
Date date = new Date(time);
out.write(date.toLocaleString());
}
}
}else {
out.write("这是第一次访问");
}

Cookie cookie = new Cookie("loginTime", System.currentTimeMillis()+"");
resp.addCookie(cookie);
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doGet(req, resp);
}
}

Session

在web.xml中可以配置session的一些配置

1
2
3
4
<session-config>
<!-- 15分钟失效 -->
<session-timeout>15</session-timeout>
</session-config>

实现session中读取数据功能

存数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class SessionDemo extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//解决乱码
req.setCharacterEncoding("UTF-8");
resp.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=utf-8");

//得到Session
HttpSession session = req.getSession();

//给Session中存东西
Person xianbei = new Person("xianbei", 20);
session.setAttribute("name",xianbei);

//获取Session的ID
String id = session.getId();

//判断Session是不是新创建
if(session.isNew()){
resp.getWriter().write("session创建成功,id:"+session);
}else{
resp.getWriter().write("session已经存在");
}
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}

取数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class SessionDemo02 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//解决乱码
req.setCharacterEncoding("UTF-8");
resp.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=utf-8");

//得到Session
HttpSession session = req.getSession();

//获取Session
Object name = session.getAttribute("name");
resp.getWriter().write(name.toString());
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}

JSP

jsp原理

Java Server Pages

https://cloud.tencent.com/developer/article/1174274

JSP其实是对Servlet进行了包装而已。
jsp + java类(service、javabean)+ servlet,就会构成mvc的开发模式,mvc模式是目前软件公司中相当通用的开发模式。

image-20220303085421-wqpfc5h.png

浏览器向服务器发出什么请求,都是在访问Servlet

1.判断请求

2.内置一些对象

jsp基础语法和指令

https://www.cnblogs.com/qlqwjy/p/8943061.html

maven配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<!--Servlet依赖-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<!--jsp依赖 -->
<!-- https://mvnrepository.com/artifact/javax.servlet.jsp/javax.servlet.jsp-api -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.1</version>
<scope>provided</scope>
</dependency>
<!-- JSTL表达式依赖 -->
<!-- https://mvnrepository.com/artifact/javax.servlet.jsp.jstl/jstl-api -->
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>jstl-api</artifactId>
<version>1.2</version>
</dependency>
<!-- standard标签依赖 -->
<!-- https://mvnrepository.com/artifact/taglibs/standard -->
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>

JSP表达式

将程序的结果输出到客户端

1
2
3
4
5
6
7
8
9
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
</head>
<body>
<%= new java.util.Date()%>
</body>
</html>
1
<%= 变量或者表达式 %>

JSP脚本片段

1
2
<%
%>
1
2
3
4
5
6
7
<%
int sum = 0;
for (int i = 0; i < 10; i++) {
sum+=i;
}
out.print(sum);
%>

JSP声明:会被编译到JSP生成的类中,其他的会被生成到_jspService方法中

1
2
<%!
%>

JSP注释(在查看页面源码的时候不会看见)

语法 描述
<%– 注释 –%> JSP注释,注释内容不会被发送至浏览器甚至不会被编译
HTML注释,通过浏览器查看网页源代码时可以看见注释内容
<% 代表静态 <%常量
%> 代表静态 %> 常量
' 在属性中使用的单引号
" 在属性中使用的双引号

JSP指令

JSP指令用来设置与整个JSP页面相关的属性。

指令 描述
<%@ page … %> 定义页面的依赖属性,比如脚本语言、error页面、缓存需求等等
<%@ include … %> 包含其他文件
<%@ taglib … %> 引入标签库的定义,可以是自定义标签

JSP标签(行为)

语法 描述
jsp:include 用于在当前页面中包含静态或动态资源
jsp:useBean 寻找和初始化一个JavaBean组件
jsp:setProperty 设置 JavaBean组件的值
jsp:getProperty 将 JavaBean组件的值插入到 output中
jsp:forward 从一个JSP文件向另一个文件传递一个包含用户请求的request对象
jsp:plugin 用于在生成的HTML页面中包含Applet和JavaBean对象
jsp:element 动态创建一个XML元素
jsp:attribute 定义动态创建的XML元素的属性
jsp:body 定义动态创建的XML元素的主体
jsp:text 用于封装模板数据
1
<jsp:include page="date.jsp" flush="true" />

JSP九大内置对象

对象 描述
request HttpServletRequest类的实例
response HttpServletResponse类的实例
out PrintWriter类的实例,用于把结果输出至网页上
session HttpSession类的实例
application ServletContext类的实例,与应用上下文有关
config ServletConfig类的实例
pageContext PageContext类的实例,提供对JSP页面所有对象以及命名空间的访问
page 类似于Java类中的this关键字
Exception Exception类的对象,代表发生错误的JSP页面中对应的异常对象

JSP四大作用域

page、request、session、application

JSTL核心标签

https://www.runoob.com/jsp/jsp-jstl.html

JavaBean

实体类

有特定的写法

  • 必须有个无参构造
  • 属性必须私有化
  • 必须有对应的get和set

一般用来和数据库的字段做映射

ORM:对象关系映射

  • 表——类
  • 字段——属性
  • 行记录——对象

MVC

https://openhome.cc/Gossip/Spring/MVC.html

image-20220303161543-ctzr0eo.png

过滤器Filter

用来过滤网站的数据

  • 处理中文乱码
  • 登录验证

过滤器中的所有代码,在过滤特定请求的时候都会执行

必须要让过滤器继续通行filterChain.doFilter(servletRequest, servletResponse);

实现一个编码转换过滤器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import javax.servlet.*;
import java.io.IOException;

public class CharacterEncodingFilter implements Filter {


@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("初始化——————");
}

@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
servletRequest.setCharacterEncoding("UTF-8");
servletResponse.setCharacterEncoding("UTF-8");
servletResponse.setContentType("text/html;charset=UTF-8");

System.out.println("执行前");
filterChain.doFilter(servletRequest, servletResponse);//让请求或相应继续通行
System.out.println("执行后");
}

@Override
public void destroy() {
System.out.println("销毁——————");
}
}

web.xml中注册过滤器

1
2
3
4
5
6
7
8
<filter>
<filter-name>character</filter-name>
<filter-class>com.kuang.filter.CharacterEncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>character</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

监听器

实现一个监听器的接口,监听器有很多种,选择我们需要的接口即可