【java】java笔记

Java小学期笔记

Java vs C++

1, 数据类型

​ *基本数据类型:byte(8bits) short(16bits) int(43bits) long(64bits) float(32bits) double(64bits) char(16bits) boolean

​ char string 用unicode编码格式(双字节编码) -可表示字母 汉字 日文等

1
2
3
4
char c = '\u0065';
// 禁止 大数据类型给小数据类型赋值-syntax error
float f = 3.14F; // (数值类型默认double)
int i = 011; // 八进制

​ *引用数据类型: Object (every thing is Object )

2, 参数传递

​ 只有传值一种方式

3, 对象存储与访问

​ 除非用new创建对象,否则,实际上并未获得任何对象

​ 对象全部存储在堆中,栈中没有对象, 访问对象的唯一方法是 ‘引用’(引用的大小:8byte)

4, 对象回收

​ 没有引用的对象 是垃圾对象,JVM的垃圾回收机制将自动回收,但不知道何时进行。(System.gc()仅是发一个回收请求,并不立刻进行)

Java中的运算

1, 算术运算

+; -; *; /; %; ++; --;>> (右移,保证符号位不变); >>> (无符号右移,最高位只补零。注意:负数移位会变成正数); & (与); | (或);^ (异或); ~ (按位取反);

1
2
3
4
5
6
7
8
9
10
11
12
int i = -1;
i = i >> 99;
// -1的补码是全1,右移保证符号,故i移位后仍为-1
int j = 17;
j = j << 33; // int只占32位,编译器会自动给33取32的模,于是等价于 j<<1
/*若是byte,short,char类型(是int型兼容的)进行算术运算,会自动进行类型提升,至int*/
// 故 byte,short,char的移位运算,移的位数仍然模32,而不是8,16
short s = 5;
s = (short) (s + (byte)9f);
int i = 1000;
byte b = (byte)i; // 输出-24 (截断后最高为为1,则为负数)
//两个byte相与,类型为int,还需转换类型

特别地,对于 = (赋值运算),基本类型的赋值运算就是普通的内容复制;而对象的赋值实际上是将“引用”从一个地方复制到另一个地方,操纵的是“引用”

2, 关系运算

<; >; <=; >=; ==; !=; instanceof;

instanceof用来在运行时指出对象是否是特定类(自己定义的)的一个实例。通过返回一个布尔值来指出,这个对象是否是这个特定类或者是它的子类的一个实例。(任何 对象 instanceof Object 结果为true,除了null)

1
2
3
4
5
6
7
Unit u = new Unit();
if(u instanceof Object) {
System.out.println("True");
}else {
System.out.println("False");
}
// 输出 True
3, 逻辑运算

&&(逻辑与); ||(短路); & (与); | (或);^ (异或);

(思考:位与运算&和逻辑与&&的区别, 位或运算|和短路运算||的区别)

1
2
3
4
5
6
7
int i = 1;
false & i++ > 10
false && i++ > 10
//两者的区别是 最终的i值不同
//常见的安全代码-利用||处理空指针异常
String username;
if(username == null || username.length()==0){//发出警告}

*桶排序 进制问题

static关键字

当声明一个事物是static时,就意味着这个域或方法不会与包含它的那个类的任何对象实例关联在一起。

具体体现是:

  • 不用创建类就可以直接通过"类名. "来访问
  • static的域是共享的,而与包含它的对象的实例个数无关(static字段对每个类来说只有一份存储空间,而非static字段则是对每个对象有一个存储空间)
  • static方法不能直接调用其他非static的域或方法

用于进行类的组织,处理命名冲突。包的命名须全小写(规范),不能以系统包名开头。

如果有包名,那么javac编译必须要加 -d 表示建立 package a.b; 中的 a.b 对应的文件夹 a (点) 表示 在当前路径下

java命令中给出 -classpath 选项,将在指定目录下去找class文件运行

jar 命令用于归档打包

*mainfest文件, 清单

继承,多态,接口

java中的继承是单一继承,若不显示指示则继承于Object

super 特指继承下来的父类(可多级),super() 仅能用于子类构造函数中,而super. 方法可以在子类其他函数中使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class A {
int j;
A() { this.init(); } // 2,此时调用的不是A的init()函数,而是B重写的init()
public void init() {
System.out.println("q");
j = 0;
}
}
class B extends A {
int j;
B(int j) { this.j = j; } // 1,子类构造函数在基类构造之后,其实j赋值之前 默认有super()
public void init() { // 3,此时调用该函数时,j并没有被赋值,默认初值为0
System.out.println("p");
System.out.println(j);
j = 4;
}
public static void main(String[] a) {
System.out.println(new B(5).j);
}
}
// 最终的输出是 p 0 5

多态分为静态多态和动态多态。静态多态也叫重载,即同名函数,参数不同;Override 重写,在继承过程中,子类重写覆盖父类中的函数。 加final 或static 明确地在编译的时候确定,该函数在继承过程中将不进行重写,可提升性能。

函数覆盖的三个原则:

​ 覆盖函数的访问权限不能比被覆盖的函数低

​ 覆盖函数抛出的检查异常不能更多(不能抛出未声明的检查异常,运行异常如NullPointerException可以)

​ static,final函数不能被覆盖

集合

java.util包下

集合最先只是定义了接口,Collections是大多数集合的公共基类

  • List:回去看文档 Object 的hasCode
  • Set:
  • Map:

泛型

文件操作

*为了保证灵活性和可扩展性,尽量少用常量(如文件名,且不用绝对路径)。

File f = new File("a.dat"); 并不是创建了一个文件,而是在内存中创建了一个File对象

RandomAccessFile可进行读写,seek

流对象: 输入输出流

1
2
3
4
5
6
// 流连接
FileInputStream fis = new FileInputStream(args[0]);
BufferInputStream bis = new BufferInputStream(fis);
DataInputStream dis = new DataInputStream(bis);

double d = dis.readDouble();

windows 是小端,而mac 大端(不同操作系统,大小端可能也不同)

*ObjectInputStream

java.io.Serializable 序列化接口,没有抽象方法(即标签接口),只是声明一下该对象是可序列化的,jvm可以在流中输出该对象

对象的.clone()是浅复制,若要自己实现深复制则可以利用文件(ObjectOutputStream)的序列化和反序列化来实现

文本文件 .dat .txt .docx .pdf 等。 汉字编码2字节, 编码格式GB2312---GBK---GB18030

Unicode字符编码,2字节,java是统一编码Unicode; utf-8 是可变长编码 基本的Unicode占1字节,中文3字节

FileReader fr = new FileReader("a.txt"); 这个类使用的编码是与平台有关的(平台默认的编码)

1
2
3
// 通常的方法
FileInputStream fis = new FileInputStream("a.txt");
BufferedReader br = new BufferedReader(new InputSreamReader(fis));

write时, ,可以使用PrintWriter的println函数跨平台地去处理换行

Properties 实现配置文件的读写

异常处理

Exception, Error 继承于Throwable, Error是致命的错误,机器直接停止运行/宕机,不说去处理它而出现异常,需要去处理。

对RuntimeException 编译器不做任何语法检查:

  • NullPointerException(空指针异常)
  • ArithmeticException(算术异常)
  • ClassCastException(类转型异常)
  • IndexOutOfBoundsException(下标越界异常)
  • ...

而对CheckException 编译器会做语法检查。

  • FileNotFoundException
  • IOException
  • SQLException
  • ...

多线程编程

必要的时候,经常进行一下Thread.sleep(), 睡眠时间可能会长于规定的时间,因为sleep()后线程重新向处理器请求调度

创建线程的两种方法:

  1. 实现Runnable接口传入Thread构造函数
  2. 继承Thread类实现run()方法

多线程的同步:synchronized 每一个对象都有一个对象锁

1
2
3
4
Objecct lock1 = new int[0];
synchronized(Obejct o){
...
}

wait() 封装在Obejct中,调用该函数的对象必须持有该对象的对象锁

notify() 与 notifyAll() : 唤醒当前对象锁处于wait()状态的线程 * 进入wait()的条件(阻塞条件)应该用while

notifyAll() 唤醒所有处于阻塞状态的线程,但进入阻塞是用的while,可以带来更好的安全性

*对象池 Object 的wait() , notify() , notifyAll()

ThreadLocal类,内部用Map来存储不同的线程变量,key: 线程 value: 变量。 可以用来隐含地参数传递。

组合与聚合:与主体生命周期一致的称为组合,组合是更强烈的聚合

*派生属性占用内存,而且致命的是派生属性的同步问题!!

网络编程

Socket 以流的方式进行数据传输 (json数据格式)

服务器端,ServerSocket 指定监听的端口, .accept() 接收客户端请求,实施监听进行阻塞

(可先发一个整数,在服务器端进行功能选择) 传送文件之前, 先把文件名, 文件长度发给对方

readFully() 缓冲区数据有多长就读多少

&小技巧:“upload”.equals(command) 有效防止了空指针异常

*工厂模式

服务器支持多并发:while 中不停地接收请求创建Socket, 创建的每一个Socket给一个线程(提前创建线程池)去处理。线程由线程池中取出,提高效率。 线程中run() 第一条应该是wait() , 收到请求后处理相应的逻辑

HashMap 是线程不安全的, HashTable 是线程安全的。 可用下面方法将集合转换成线程安全的

Map map = Collections.synchronizedMap(map);

TreeSet, TreeMap 中若有自定义的对象,则对象要实现Comparable接口,以进行比较

事件处理机制

event (接口), event source (事件源)

ActionEvent, MouseEvent, KeyEvent, FocusEvent

event都有一个函数getSource()方法

*java 命令行参数 -D可以设置系统属性 ,如用FileReader来读文件是与平台有关的,若想在日文系统中读中文文本,则可以 java -Dfile.encoding=gbk 类 来运行

*装饰者模式

注解

常用的注解:@Override @Deprecated @SuppressWarnings (用于压制程序中的警告,有{“unchecked", "Deprecated"}等)

使用@interface Annotation{ }

一个@Annotation注解,一个注解是一个类

动态地根据类名创建实例:(类名)Beans.instantiate(ClassLoad cl, String className)

参考:https://blog.csdn.net/liuwenbo0920/article/details/7290586

import static 类 :表示导入该类所有的静态方法(原来Math.abs(),现在只用abs() )

*java.lang.reflect

*TLV (TAG-LENGTH-VALUE) 变长数据传输的一种报文格式

JDBC

创建完Connection之后,java会自动进行事务提交(con.commit()),若要自己提交事务则要在此处设置 con.setAutoCommit(false);

分布式事务(例子:跨行取钱),使用2PC来支持分布式事务

o/r mapping 对象关系 映射

*软件设计的一些原则: 开闭原则,依赖倒置原则,里氏替换原则,接口隔离原则

J2EE笔记

tel: 18640857288 qq: 1458233700 email: jgh@dlut.edu.cn

介绍

j2ee是java se 的扩展,包名均以javax开头。java SE(桌面应用), java EE(企业应用), java ME (嵌入式应用)

javaEE平台很多都是接口,是一个抽象的平台称为“定义平台”。

基于组件的开发,组件(如servlet)在容器中被调用。应用服务器软件:开源免费: Apache-tomcat, 收费:IBM-WebSphere Application Server (WAS ); Bea WebLogic

没有main函数,需要将项目部署(deploy)到Web服务器。打包成.war文件。

*URL的格式(三个部分):协议+主机(IP+端口)+文件路径 (例如: https://127.0.0.1:8080/SearchPage/index.html?username=zzmine&password=123456)。 url地址中?后面的内容叫作 查询字符串(Query String)

request和response的组成:headers和content,用两次回车换行分隔()

Servlet

[interface] 用于处理请求和发送响应,实现动态页面。

组件不能自己写构造函数,应用服务器会使用默认构造函数!!若要构造,应该重写其init(ServletConfig config)函数。HttpServlet已经实现了init()方法。

1
2
3
4
5
6
7
8
9
10
11
//两种init方法
//1,带参数
public void init(ServletConfig config){
super.init(config);
...
}
//2,不带参数
public void init(){
...
}

Servlet的service()方法,参数,返回类型以及抛出什么异常。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException{
HttpServletRequest req = (HttpServletRequest)request;
HttpServletResponse res = (HttpServletResponse)response;
// HttpServletReuqest的getMethod方法可以获得用户请求的方式(GET,POST等)
String method = req.getMethod();
if("GET".equals(method)){
...
}else if("POST".equals(method)){
...
}

res.setContentType("text/html;charset=utf-8");
PrintWriter out = res.getWriter();
out.print("<p>Hello World</p>");
// 不建议写流的关闭,还有其他程序需要输出
// 输出形式为jpeg图片
res.setContentType("image/jpeg;charset=utf-8");
OutputStream out = res.getOutputStream();
out.write(...);
}

Servlet的生命周期

1
2
3
4
5
(1)web容器加载Servlet,生命周期开始。(仅调用一次)说明Servlet是单实例的
(2)调用servlet的init()方法,servlet初始化。(仅调用一次)
(3)调用service()方式,处理请求(被多次调用)
(4)结束服务,web容器调用servlet的destory()方法(仅调用一次)

部署(deploy)的方法:

1, 将web应用(HelloServlet)直接复制在Tomcat的WebApps文件夹下, 则用户访问路径:http://localhost:8080/HelloServlet/abc/h.html

2, 在Tomcat配置中的server.xml下部署:在Host元素下建子标签 。path是url,docBase是文件的物理地址。则用户访问路径: http://localhost:8080/abc/abc/h.html

1
2
3
4
5
6
7
8
9
10
11
12
13
<servlet>
<servlet-name>HelloWorld</servlet-name>
<servlet-class>com.a.HelloWorld</servlet-class>
</servlet>
<!--备注:同一个Servlet可以被映射到多个URL上,配置多个servlet-mapping-->
<servlet-mapping>
<servlet-name>HelloWorld</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<!--
url-pattern可以使用通配符,但既有斜杠又有扩展名是不合法的,如/*.html
-->

*javax.websocket包下,Endpoint, Encoder, Decoder。双向发送数据,而Servlet是请求应答式单向的服务。

ServletConfig, ServletContext

ServletConfig有两个重要的方法:

  • getInitParameter(String name) -获得初始化参数name的值,若没有对应于name的参数,那么返回null
  • getServletContext() -获得代表应用全局的ServletContext类

ServletContext中有一系列add,set,get方法,用于Servlet与container的交流,可以当成一个web应用中所有构件的共享资源

该对象代表当前的web应用,可以从中获取到该web应用的各种信息 ① 配置,获取 web应用的初始化参数 该初始化参数可以被所有Servlet获取,而Servlet的初始化参数只供那个Servlet获取 在< web-app> 中配置 < context-param> servletContext.getInitParameter()

② 获取当前web应用某个文件在服务器上的绝对路径,而不是部署前的路径: getRealPath(String path)

③ 获取当前web应用的名称: getContextPath() 若web应用直接放在root目录下,则request.getContextPath()返回为空串。

④ 获取当前web应用的某一个文件对应的输入流 getResourceAsStream(String path) path的 / 是相对于当前web应用的根目录

⑤ 跟attribute相关的几个方法

https://blog.csdn.net/wangqing84411433/article/details/71131608 1、在web.xml配置文件中,对个servlet的配置里,有一项< load-on-startup> < /load-on-startup>,它的含义是:标记容器是否在启动的时候就加载这个servlet。当值为0或者大于0时,表示容器在应用启动时就加载这个servlet;当是一个负数时或者没有指定时,则指示容器在该servlet被选择时才加载。正数的值越小,启动该servlet的优先级越高。

servlet_2虽然配置在servlet_1后面,但是它的load-on-startup为0,启动的优先级高于servlet_1,所以servlet_2先启动。

2、获取ServletContext的两种方式,直接获取 this.getServletContext()和间接获取config.getServletContext,得到的对象都是同一个。同时在servlet1和servlet2中取得的ServletContext对象都是同一个对象,说明整个web应用都只有一个唯一的ServletContext实例

3、servlet1与servlet2的serveletConfig对象是不一样的,说明ServletConfig对象的作用范围仅在servlet中。

HttpServlet [abstract class]: 不去重写service()方法,而是去override doGet(), doPost()之类的方法。在多线程中注意并发资源的保护

在doGet()方法中注意处理content type以及encoding

1
2
3
4
5
6
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{ }

protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{ }

public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException{ }

ServletRequest [interface]:

HttpServletRequest [interface]: 继承ServletRequest,为Http servlet提供请求信息。

该对象提供的数据包括,参数名称和值,属性以及输入流

1
2
3
4
5
6
7
Object getAttribute(String name){ }   // 从request域中取出对应name的数据
String getParameter(String name){ } // 从url中获取对应name的查询字符串的值,如果name参数不存在则返回null
String[] getParameterValues(String name){} // 对应name的多个值
String getMethod(){} // 获得请求方式
HttpSession getSession(){} // 返回Session
ServletContext getServletContext(){} // ServletRequest中的方法

ServletResponse [interface]:

HttpServletResponse [interface]: 继承ServletResponse,在发送响应式提供特定于http的功能。

用于向客户端返回数据。若要返回字符数据,可以通过getWriter()方法返回的PrintWriter对象来操作,它的write()方法不会抛出异常

1
2
3
4
void setCharacterEncoding(String charset){}    // 设置response的字符编码,如utf-8
void setContentType(String type){ } // 设置response的内容格式,给定的内容可以包含字符编码规范。例如 “text/html;charset=utf-8” 如果在调用getWriter之前调用此方法,则仅从给定的内容类型设置响应的字符编码
// 注意: This method has no effect if called after the response has been committed. It does not set the response's character encoding if it is called after getWriter has been called or after the response has been committed.

Session

HttpSession Api

可以设置session的生存/超时时间,但注意单位。tiemout通常单位是分钟。

session在内存中如何被创建?

*memcached分布式缓存

HttpSession底层实现的三种方法(https://blog.csdn.net/qfs_v/article/details/2652119):

  1. *cookie技术
  2. URL重写(rewrite) (浏览器不支持cookie时,可以用URL重写来代替)
  3. 隐藏表单域 (form表单有一个隐藏的input)

Annotation: 参考https://j2eereference.com/webservlet-annotations/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.*;
import javax.servlet.annotation.*;

@WebServlet(value="/hello",
initParams = {
@WebInitParam(name="param1", value="Hello "),
@WebInitParam(name="param2", value=" World!")
})
public class HelloServlet extends GenericServlet {

public void service(ServletRequest req, ServletResponse res)
throws IOException, ServletException
{
PrintWriter out = res.getWriter();
out.println(getInitParameter("param1"));
out.println(getInitParameter("param2"));
}
}

RequestDispatcher

用于请求转发,页面重定向。

1
2
3
4
5
//Forwards a request from a servlet to another resource (servlet, JSP file, or HTML file) on the server.
public void forward(ServletRequest request, ServletResponse response) throws ServletException,IOException
//Include: 将当前请求派发到另一个组件,处理完毕后,回到该组件
public void include(ServletRequest request, ServletResponse response) throws ServletException, IOException

若需要传送数据到另一个组件,不要在response的输入输出流中进行,可以利用request.setAttribute()方法,在request域中存放数据。

注意:路径中'/'表示应用的根目录。request的请求转发是应用组件内的转发。而ServeltContext的转发方法可以在用一个tomcat进程中在不同web应用进行转发。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@WebServlet("/Servlet/a");
public class AServlet extends HttpServlet throws...{
public void service(){
response.setContentType("text/html;charset=utf-8");
// !response.getWriter().print("...1");
// text/html MIME类型

request.setAttribute("obj",obj);
request.getRequestDispathcer("/Servlet/b").forward(request,response);
// !response.getWriter().print("88");
// 若是forward方法,则不能在response的输出流中输出(该组件不能处理response流),应该将要输出的对象先存在reqeust域中,再传给另一个组件。
}
}

(必考) response的sendRedirect与request的转发的区别:

1
2
3
request的是由服务端进行转发的,浏览器地址栏不变,只发出一次请求
response的是由客户端进行重定向,浏览器地址栏会改变,相当于发多次请求,效率较低

Filter

(必考) Filter,其服务函数doFilter(),在Servlet运行之前执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public void doFilter(ServletRequest r1, ServletResponse r2, FilterChain chain) throws ServletException{

long start = System.currentTimeMillis();
HttpServletRequest request = (HttpServletRequest)r1;
HttpServletResponse response = (HttpServletResponse)r2;
// 预处理

// 过滤后,交给Servlet,最后进行后处理。若没有chain.doFilter(),那么该Filter就会产生拦截,不会访问到后面的Servlet
chain.doFilter(requeset,response); // 往后传

//后处理
long end = System.currentTimeMillis();
}

FilterChain: 用来唤醒下一个filter

1
2
Filter use the FilterChain to invoke the next filter in the chain, or if the calling filter is the last filter in the chain, to invoke the resource at the end of the chain.

按提供的服务分类有:

  1. Authentication Filters
  2. Logging and Auditing Filters
  3. Image conversion Filters
  4. Data compression Filters
  5. Encryption Filters...

Filter的拦截配置:

1
2
3
4
5
6
7
8
9
10
<filter>
<filter-name>f4</filter-name>
<filter-class>a.MyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>f4</filter-name>
<servlet-name>hello</servlet-name> <!--拦截某个servlet-->
<url-pattern>/sss/*</url-pattern> <!--url模式拦截-->
</filter-mapping>

两个过滤器,EncodingFilter负责设置编码,SecurityFilter负责控制权限,服务器会按照web.xml中过滤器定义的先后循序组装成一条链,然后一次执行其中的doFilter()方法。执行第一个过滤器的chain.doFilter()之前的代码,第二个过滤器的chain.doFilter()之前的代码,请求的资源,第二个过滤器的chain.doFilter()之后的代码,第一个过滤器的chain.doFilter()之后的代码,最后返回响应。

1
2
3
4
5
6
7
// 这个路径仍然是绝对路径
File file = new File("/WEB-INF/contact/a.txt");
// 这个是可以将web应用的根路径转换成操作系统的路径
String s = getServletContext().getRealPath("/WEB-INF/contact/a.txt");
// 若打包到war,这样的路径仍是不对的,可以下面或ClassLoader
InputStream in = getServletContext().getResourceAsStream("/WEB-INF/contact/a.txt");

分页功能,List的subList方法,取出子集合

listener

1577624122812

构造listener,要么适用WebListener进行注解声明,要么使用ServletContext的addListener()方法进行添加。

1
2
3
4
5
6
7
8
9
10
11
12
13
@WebListener
public class ApplicationIntializer implements ServletContextListener{
//在filter以及servlet之前,ServletContextListener会收到servlet
public void contextInitialized(ServletContextEvent sce){
ServletContext context = (ServletContext)sce.getServletContext();

DataSource ds = ...;
}
public void contextDestroyed(ServletContextEvent sce){
...
}
}

ServletContextEvent仅有一个方法——getServletContext(),返回改变了的ServletContext(发送event的那个ServletContext)

它的父类EventObject还有一个getSource()的方法。

HttpSessionBindingEvent的getValue()返回旧的值

Jsp

Jsp本质上是Servlet,是服务器中的组件。tomcat运行jsp时将其转化为.java再编译为.class文件。

JspPage类的生命周期:jspInit(), jspDestroy()

HttpJspPage的服务函数,_jspService(HttpServletRequest request, HttpSerletResponse response){}

二加一方法:

_jspService()方法依赖于特定的协议,因此在java中并不是通用的方法

1
2
3
// time.jsp
<%= new java.util.Date()%>

jsp文件内嵌java代码,语法包括,jsp指令,jsp声明,jsp表达式,jsp注释,jsp脚本

1
2
3
4
5
6
<%@     %>				jsp指令的语法(三大指令:page,include,taglib)
<%= %> jsp表达式的语法
<%! %> jsp声明的语法
<%-- --%> jsp注释
<% %> jsp中内嵌java代码 ()

(必考)jsp的九个隐式对象:

1569217469521

exception用在错误处理页面,在声明了isErrorPage="true"时,才能使用

(重点1)JspWriter

jsp中的数据和模板都是用JspWriter来输出的,由隐式对象out来引用。

  1. 与System.out.println以及response.getWriter().print()的区别:JspWriter会抛出异常,IOException。记得一定要try-catch。而PrintWriter并不会抛出异常。
  2. out对象存在一个新的缓冲区

(重点2)PageContext

fascade pattern 门面模式,将复杂的系统功能抽象为一个“门面”——更加友好的接口。PageContext封装了jsp在运行过程中使用的所有对象。将jsp的对象传给java只需要一个pageContext,由此可以获得其他八个隐式对象。

(注意)下面的程序可能会有NullPointerException

1
2
3
4
5
6
7
<%
String parameter = request.getParameter("page");
int page = Integer.paraseInt(parameter);
%>
// http://localhost:8080/SearchPage?page=&id=22
// 若url中有page=但没有参数,那么返回空串;若没有page=则返回null

(注意)jsp声明一般不声明变量,因为在并发情况下这些变量是不安全的,除非加上syncronized修饰

1
2
3
4
5
6
7
// 页面转发
<jsp:forward page="/servlet/a" />
<%
request.getRequestDispatcher("/servlet/a").forward(request,response);
pageContext.forward("/servlet/a");
%>

(考) 与 <%@ include file="/serlvet/a"%>的区别,第二个是在编译时包含——静态包含,只能包含静态文件,在jsp转换到serlvet过程中进行包含;而第一个是动态包含。

*useBean转换到java代码

1
2
3
4
5
6
7
8
9
10
<jsp:useBean id="a" class="com.abc.bean.Student" scope="page|request|session|application" />
// 猜数游戏的javaBean应该在session域中
// jsp中取对象属性
<jsp:getProperty name="a" property="age" />
<%= a.getAge() %>
${a.age}
// 设置属性
<jsp:setProperty name="a" property="age" value="26"/>
<jsp:setProperty name="a" property="*" />

注意:javaBean的属性都是小写开头!

1
2
3
4
5
// (考试坑)
<input name="Age"></intput>
<jsp:setProperty name="a" property="age" param="Age"/>
// 注意param与html中name的大小写!

另外,jsp也支持简化的表达式语言(EL),使输出数据更方便${expression}

脚本变量从pageContext, request, session, application这四个作用域中自动依次寻找,如果没有定义,就什么也不输出,不报错。

pageContext:属性作用范围仅限于当前JSP页面 request:属性作用范围仅限于同一个请求 session:属性作用范围限于一次会话,浏览器打开直到关闭称之为一次会话(在此期间会话不失效) application:属性作用范围限于当前web应用,是范围最大的属性作用范围

EL表达式预定于了11个对象,除了pageContext对象是PageContext类型(考试重点),其余都是Map类型(考试必考)

1
2
3
4
5
6
7
8
9
10
11
12
pageContext
param
paramValues
header
headerValues
cookie
initParam
pageScope
requestScope
sessionScope
applicationScope

*MVC(模型-视图-控制器)

分页逻辑:定义一个PageBean,对分页所需要的数据进行管理

自定义标记

(javax.servlet.jsp.tagext)

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
// 标记处理器类

import ...
import javax.servlet.jsp.tagext.*;

/*public class TimeTag extends TagSupport{

public int doStartTag() throws JspException{
// pageContext是TagSupport中的保护成员
JspWriter out = pageContext.getOut();
out.println(new Date());
// 但是此时需要对JspWriter做异常处理
// 不过这里只能通过try-catch来解决
}

}*/

// SimpleTag不提供doStartTag()和doEndTag()方法,而是提供了更简单的doTag()方法,有更简单的生命周期和接口

public class ATag extends SimpleTagSupport{
pubilc String color = "black";
public void getData(string data){
this.color = data;
}

public void doTag() throws JspException, IOException{
JspWriter out = getJspContext.getOut();
...
}
}

Tag handler

...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// tag的配置  ---创建标签库
// WEB_INF/a.tld
<tag-lib>
// 给整个标记库定义一个名字
<uri>Http://www.abc.com/javaee</uri>
<tag>
<name>reset</name>
<tag-class>ResetTag</tag-class>
<body-content>JSP</body-content>
</tag>
</tag-lib>

// 引入到jsp中的方法(必考)
<%@ taglib uri="\WEB-INF\a.tld" prefix="t"%>
// 若用网上下载的,只有jar包,那么使用整体定义的名字,支持打包
<%@ taglib uri="Http://www.abc.com/javaee" prefix="t"%>

*xml命名空间

(问答题)与数据库建立连接时,两种类加载方式的区别:

1
2
3
4
5
// 1, 这种方式需要在编译前就把类放到classpath中
Driver driver = new com.mysql.jdbc.Driver();
// 2, 通过反射机制
Class.forName("com.mysql.jdbc.Driver");

JNDI

(必考)Java命名和目录接口(Java Naming and Directory Interface ,JNDI)。主要功能:注册,查找.

JNDI的功能简单说就是可以用简单的方式去查找某种资源。JNDI提供一套标准,服务商去实现SPI,去实现技术细节;程序员去调用API中的方法,不用关心怎么实现的功能。

1
2
3
4
5
// 利用命名服务来获得DataSource
Context ctx = new InitialContext();
DataSource ds = (DataSource)ctx.lookup("java:comp/env/jdbc/ExamDB");
// lookup中填写的是 java计算机环境变量 其中“java:comp/env/”为命名前缀

Structs 1

a rapid framework for web development based on JavaEE,基于MVC设计模式。降低软件的粒度,提高了Controller的复用性。分为前端控制器和后端控制器。

(曾经考题)structs 框架的配置文件名 不一定要叫 structs-config.xml

前端控制器(ActionServlet),后端控制器(Action)。控制器功能写在execute()函数中。控制器的另一个功能:选择视图输出。

1
2
3
前端控制器名称:org.apache.structs.action.ActionServlet
后端控制器名称:org.apache.structs.action.Action

Structs1开发步骤:

  1. 创建ActionForm的实现,ActionForm是数据表单的对象实现
  2. 创建Action的实现,完成其execute()方法
  3. 创建数据表单Jsp和结果Jsp
  4. 配置structs-config.xml

创建后端控制器Action,实现execute方法:

1
2
3
4
public ActionForward execute(ActionMapping actionMapping, ActionForm actionForm, HttpServletRequest request, HttpServletResponse response){

}

Action负责页面流程控制、前后台交互。将编写的Action类配置在页面流程控制struts-config.xml:

1
2
3
4
<action name=“xxxForm” path=“/xxxAction” scope=“request“ type="com.jdon.XxxViewAction">
  <forward name="forward" path="/xxx.jsp" />
</action>

*(考)DispatchAction (由汇聚到支流),降低Action数量

Struts1的工作流程:

  • 客户端发送请求(Http Request),被struts1的核心控件器ActionServlet接收,ActionServlet根据 struts-config.xml里的映射关系找到对应的Action,若找不到就返回500错误到JSP页面。若有就在 Action里的 excute()方法里执行相应的逻辑操作,比如调用Model层的方法,然后通过ActionForward,跳转到对应的JSP页面。

Structs 2

使用structs 2 的步骤:

  1. 创建文件夹目录结构:1570858700925
  2. 导入structs2,import struct 2
  3. config, deployment

structs2的简单处理流程:

1
2
3
4
5
6
1)浏览器发送请求
2)中心处理器(FilterDispatcher)根据struts.xml文件查找对应的处理请求的Action类
3)WebWork的拦截器链自动对请求应用通用功能,例如:WorkFlow、Validation等功能
4)如果Struts.xml文件中配置Method参数,则调用Method参数对应的Action类中的Method方法,否则调用通用的Execute方法来处理用户请求
5)将Action类中的对应方法返回的结果响应给浏览器

structs 1 与 structs 2的区别:

1
2
3
4
5
6
1)Action类的实现方式:Struts1的Action在实现的时候必须扩展Action类或者Action的子类(DispatchAction),Struts2的Action类实现的时候可以不用实现任何类和接口
2)Struts1的Action类是单例模式,必须设计成线程安全的,Struts2则为每一个请求产生一个实例
3)Struts1的Action类依赖与Servlet API,execute方法有HttpServletRequest和HttpServletResponse,Struts2则不依赖于Servlet API;
4)Struts1的Action与View通过ActionForm或者其子类进行数据传递 而struts2去掉了formbean
5)Struts1绑定了JSTL,为页面的编写带来方便,Struts2整合了ONGL,也可以使用JSTL

ResourceBundle 支持国际化,

Spring

是一个轻量级控制反转(IoC)和面向切面编程(AOP)的容器。

(考试)什么是IoC,DI?

1
2
3
IoC(Inversion of Control)控制反转:将对象的生命周期控制,交给第三方容器
DI(Dependency injection)依赖注入:组件之间的依赖关系由容器在运行期决定,即 由容器动态地将某种依赖关系注入到组件之中

*工厂模式, 工厂方法模式, 抽象工厂模式

(考)ClassPathXmlApplicationContext ,FileSystemXmlApplicationContext 前者的xml文件在classpath中(支持打包),后者通过绝对路径指定xml文件。

web应用中创建spring容器,使用XmlWebApplicationContext。听众接口:ServletContextListener,其中两个事件处理函数,

1
2
3
4
5
6
7
8
// 必考要记
public void contextInitialized(ServletContextEvent sce){
Context ctx = new InitialContext();
DataSource ds = (DataSource)ctx.lookup("java:comp/env/jdbc/ExamDB");
sce.getServletContext().setAttribute("ds",ds);
}
public void contextDestroyed(ServletContextEvent sce){}

*(必考)web.xml中声明一个组件:

1
2
3
4
5
6
<web-app>
<listener>
<listener-class></listener-class>
</listener>
</web-app>

AOP编程

(任务)

1
2
3
4
5
6
7
8
理解BeanFactory
理解ApplicationContext
理解FileSystemXmlApplicationContext
理解ClassPathXmlApplicationContext
理解XmlWebApplicationContext
重点理解JavaEE Web Application如何集成Spring框架
理解Spring framework的配置

spring mvc 前端控制器的mapping 不要使用/* , 而应该使用/ (优先级最低) ,否则会拦截.jsp

SpringMVC

基本处理流程:

1577616911675
  1. 用户请求首先发送到前端控制器DispatcherServlet,DispatcherServlet根据请求的信息来决定使用哪个页面控制器Controller来处理该请求。找到控制器之后,DispatcherServlet将请求委托给控制器去处理。
  2. 接下来页面控制器开始处理用户请求,页面控制器会根据请求信息进行处理,调用业务层等等,处理完成之后,会把结果封装成一个ModelAndView返回给DispatcherServlet。
  3. 前端控制器DispatcherServlet接到页面控制器的返回结果后,根据返回的视图名选择相应的视图模板,并根据返回的数据进行渲染。
  4. 最后前端控制器DispatcherServlet将结果返回给用户。

备注:

  1. DispatcherServlet相当于前端控制器: org.springframework.web.servlet.DispatcherServlet
  2. Handler(需要自己开发)是继DispatcherServlet前端控制器的后端控制器,在DispatcherServlet的控制下Handler对具体的用户请求进行处理。
  3. 前端控制器的url-pattern应该是/,而不是/*

Spring的后端控制器可以用xml配置,也可以用注解来声明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.abc.project.controller;

@Controller
public class MyController{
// 路径到处理函数的映射
@RequestMapping("/calc/add")
public String add(@RequestParam(value="v1") String v1,
@RequestParam(value="v2") String v2){

}
}

在配置文件中开启mvc
<mvc:annotation-driven/>
在配置文件中启动扫描组件,注意是包的名字
<context:component-scan base-package="com.abc.project.controller"/>


MVC 各自的作用以及关系

1
2
3
4
5
6
7
8
9
10
View 访问模型,显示模型层的内容
Controller 前端控制器:访问View(可复用) 后端控制器: 访问模型(不可复用)
Model 模型层主要负责保存和访问业务逻辑,执行业务逻辑和操作。(不可复用)
特点:
1)多个视图可以对应一个模型,增强了了代码的重用性,减少代码量,易于维护
2)分离视图层和业务逻辑层,可维护性高
3)降低了各层之间的耦合性,提供了应用的可扩展性
4)MVC更符合软件工程化管理的精神,各层各司其职
5)使用MVC模式使开发时间得到相当大的缩减,部署加快

Hibernate

是一个对象关系映射框架,对JDBC进行了轻量级的对象封装。可以自动生成SQL语句,自动执行。

Hibernate使用反射机制实现持久化对象的操作。

0%