10000小时


  • 首页

  • 关于

  • 标签

  • 分类

  • 归档

设计模式--工厂模式

发表于 2017-10-27 | 分类于 设计模式

工厂模式:实例化对象,用工厂方法代替new操作。

简单工厂模式

简单工厂模式又称静态工厂方法模式。重命名上就可以看出这个模式一定很简单。它存在的目的很简单:定义一个用于创建对象的接口。
1) 工厂类角色:这是本模式的核心,含有一定的商业逻辑和判断逻辑,用来创建产品。
2) 抽象产品角色:它一般是具体产品继承的父类或者实现的接口。
3) 具体产品角色:工厂类所创建的对象就是此角色的实例。在java中由一个具体类实现。

产品类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
abstract class BMW{
public BMW(){
}
}
class BMW320 extends BMW{
public BMW320(){
System.out.println("create BMW320");
}
}
class BMW520 extends BMW{
public BMW520(){
System.out.println("create BMW520");
}
}

工厂类

1
2
3
4
5
6
7
8
9
10
11
class BMWFactory{
public BMW createBMW(int type){
switch (type){
case 320: return new BMW320();
case 520: return new BMW520();
default:
break;
}
return null;
}
}

调用者

1
2
3
4
5
6
7
public class FactoryPattern {
public static void main(String[] args){
BMWFactory factory = new BMWFactory();
factory.createBMW(520);
factory.createBMW(320);
}
}

工厂方式模式

工厂方法模式组成:
1)抽象工厂角色: 这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现。
2)具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。
3)抽象产品角色:它是具体产品继承的父类或者是实现的接口。在java中一般有抽象类或者接口来实现。
4)具体产品角色:具体工厂角色所创建的对象就是此角色的实例。在java中由具体的类来实现。

产品类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
abstract class Audi{
public Audi(){
}
}
class AudiA4 extends Audi{
public AudiA4(){
System.out.println("create AudiA4");
}
}
class AudiA6 extends Audi{
public AudiA6(){
System.out.println("create AudiA6");
}
}

工厂类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
interface AudiFactory{
public Audi createAudi();
}
class AudiA4Factory implements AudiFactory{
@Override
public AudiA4 createAudi(){
return new AudiA4();
}
}
class AudiA6Factory implements AudiFactory{
@Override
public AudiA6 createAudi(){
return new AudiA6();
}
}

调用者

1
2
3
4
5
6
7
8
9
public class FactoryPattern {
public static void main(String[] args){
AudiA4Factory audiA4Factory = new AudiA4Factory();
AudiA4 audiA4 = audiA4Factory.createAudi();
AudiA6Factory audiA6Factory = new AudiA6Factory();
AudiA6 audiA6 = audiA6Factory.createAudi();
}
}

工厂方法模式仿佛已经很完美的对对象的创建进行了包装,使得客户程序中仅仅处理抽象产品角色提供的接口,但使得对象的数量成倍增长。当产品种类非常多时,会出现大量的与之对应的工厂对象,这不是我们所希望的。

抽象工厂模式

为什么引入抽象工厂模式:
抽象工厂模式是工厂方法模式的升级版本,他用来创建一组相关或者相互依赖的对象。比如奔驰C200使用发动机A和铁A,而奔驰C300使用发动机型号B和铁B,那么使用抽象工厂模式,在为C200系列生产相关配件时,就无需制定配件的型号,它会自动根据车型生产对应的配件。

产品类

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
//发动机类型
interface Engine{
}
class EngineA implements Engine{
public EngineA(){
System.out.println("with EngineA");
}
}
class EngineB implements Engine{
public EngineB(){
System.out.println("with EngineB");
}
}
//钢铁的类型
interface Iron{
}
class IronA implements Iron{
public IronA(){
System.out.println("is IronA");
}
}
class IronB implements Iron{
public IronB(){
System.out.println("is IronB");
}
}

工厂类

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
//工厂接口
interface BenzFactory{
public Engine withEngine();
public Iron ironType();
}
//奔驰C200装配工厂
class BenzC200Factory implements BenzFactory{
@Override
public EngineA withEngine(){
return new EngineA();
}
@Override
public IronA ironType(){
return new IronA();
}
}
//奔驰C300装配工厂
class BenzC300Factory implements BenzFactory{
@Override
public EngineB withEngine(){
return new EngineB();
}
@Override
public IronB ironType(){
return new IronB();
}
}

调用者

1
2
3
4
5
6
7
8
9
10
11
public class FactoryPattern {
public static void main(String[] args){
BenzC200Factory benzC200Factory = new BenzC200Factory();
benzC200Factory.ironType();
benzC200Factory.withEngine();
BenzC300Factory benzC300Factory = new BenzC300Factory();
benzC300Factory.ironType();
benzC300Factory.withEngine();
}
}

总结

无论是简单工厂模式,工厂方法模式,还是抽象工厂模式,他们都属于工厂模式,在形式和特点上也是极为相似的,他们的最终目的都是为了解耦。在使用时,我们不必去在意这个模式到底工厂方法模式还是抽象工厂模式,因为他们之间的演变常常是令人琢磨不透的。经常你会发现,明明使用的工厂方法模式,当新需求来临,稍加修改,加入了一个新方法后,由于类中的产品构成了不同等级结构中的产品族,它就变成抽象工厂模式了;而对于抽象工厂模式,当减少一个方法使的提供的产品不再构成产品族之后,它就演变成了工厂方法模式。
所以,在使用工厂模式时,只需要关心降低耦合度的目的是否达到了。

关于抽象工厂模式的起源:
贴一个连接:抽象工厂的起源

设计模式--单例模式

发表于 2017-10-27 | 分类于 设计模式

单例模式的作用:保证整个应用中某个实例中有且仅有一个。

饿汉模式

类的静态成员属于类所有,一旦类加载的时候,instance实例就会被创建。
由于instance对象在类加载时候马上被创建的,所以称之为饿汉。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class HungryMan{
/*
1. 私有化构造方法,不允许外部直接创建对象
2. 创建类的唯一实例
3. 提供一个获取实例的方法
*/
private static HungryMan instance = new HungryMan();
private HungryMan(){
//...doSomething
}
public static HungryMan getInstance(){
return instance;
}
}

懒汉模式

当类加载时候,类的实例并未被创建,只有当调用者第一次使用getInstance时候,类的唯一实例才会被创建。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class LazyMan{
/*
1. 私有化构造方法,不允许外部直接创建对象
2. 声明类的唯一实例
3. 提供一个获取实例的方法
*/
private static LazyMan instance;
private LazyMan(){
//doSomething
}
public static LazyMan getInstance(){
if(instance == null){
instance = new LazyMan();
}
return instance;
}
}

####区别

饿汉模式加载类的时候比较慢,因为要创建instance实例
懒汉模式加载类的时候比较快,因为没有创建instance实例,故在第一次获取实例的时候,会比较慢。

懒汉模式是线程不安全的。
举个例子:
假设开始线程0进入,判断instance为空,在将要创建实例时,cpu切换,线程1又进来了,同样instance为空 创建了实例,这是cpu切换回来到0线程,继续创建实例。
可见,经过分析共创建了两个实例,还谈什么单例。

下面是线程安全的懒汉模式

1
2
3
4
5
6
7
8
9
10
11
12
public static LazyMan getInstance(){
if(instance == null){
//线程0
synchronized(LazyMan.class){
//线程1
if(instance == null){
instance = new LazyMan();
}
}
}
return instance;
}

为什么需要判断两次instance == nulll
假设线程0进来,卡在所示的位置,然后切换cpu,进程1卡在所示位置,那么如果不进行内层的if判断的话,instance又会被创建两次了。

Ajax

发表于 2017-10-14 | 分类于 前端

本博文不考虑不支持XMLHttpRequest对象的情况

#初识Ajax

XMLHttpRequest对象是Ajax基础

XMLHttpRequest对象

XMLHttpRequest用于在后台与服务器交换数据。这意味着可以在不重新加载整个网页的情况下,对网页进行某部分的更新。

创建XMLHttpRequest对象的语法

1
var xmr = new XMLHttpRequest();

XMLHttpRequest的请求

1
2
3
var xmr = new XMLHttpRequest();
xmr.open("GET", "myUrl", ture);
xmr.send();
1
2
3
4
5
6
方法 描述
open(method, url, async) method:请求的类型;GET 或 POST
url:文件在服务器上的位置
async:true(异步)或 false(同步)
send(string) string:仅用于POST请求

GET和POST方法的选择

与POST相比,GET更简单也更快,并且在大部分情况下能使用。
然后在以下情况使用POST请求:
>
无法使用缓存文件(更新服务器上的文件或数据库)
向服务器发送大量数据
发送包含未知字符的用户输入,POST比GET更加可靠和稳定

排序算法

发表于 2017-09-22 | 分类于 Algorithms

五种排序算法

选择排序

选择排序两个鲜明的特点:

  1. 运行时间和输入无关:为了找出最小的元素而扫描一遍数组并不能为下一趟扫描提供任何有用的信息。一个已经有序的数组或者是元素全部相等的元素和一个随机排序的数组所用的排序时间一样长。
  2. 数据移动是最少的:显然可见,移动数据只发生在是外层循环中。故选择排序只用了N次交换,这是其他大部分算法不具备的。
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
package com.algorithms;
import java.util.Arrays;
public class Sort {
private static int compareTo(double x, double y){
if(x < y){
return -1;
}
else if(x > y){
return 1;
}
else{
return 0;
}
}
private static void exchange(double[] A, int i, int j){
double temp = A[i];
A[i] = A[j];
A[j] = temp;
}
public static void selectionSort(double[] A){
int N = A.length;
for(int i = 0; i < N; ++i){
int min = i;
for(int j = i + 1; j < N; ++j){
if(compareTo(A[min], A[j]) == 1){
min = j;
}
}
exchange(A, i, min);
}
}
public static void main(String[] args){
double[] A1 = {5, 7, 1, 0, 4, 9, 2, 3, 8, 6};
selectionSort(A1);
System.out.println(Arrays.toString(A1));
}
}

插入排序

插入排序和选择排序有一个相同的地方是:当前索引左边的所有元素都是有序的。
与选择排序不同的是:插入排序所需的时间取决于排序数组中元素的初始顺序。例如,一个很大且其中的元素已经(或接近有序)的数组进行排序会比对随机顺序的数组或者是逆序数组(最坏情况)进行来的快。
特点:插入排序对于部分有序的数组十分高效,也很适合于小规模数组。

1
2
3
4
5
6
7
8
9
10
public static void insertionSort(double[] A){
int N = A.length;
for(int i = 1; i < N; ++i){
//因为[0, j-1],已经是有序
//如果当索引j大于索引j-1的值,那么数组[0, j]就是有序的,跳出循环
for(int j = i; j > 0 && (compareTo(A[j-1], A[j]) == 1); --j){
exchange(A, j-1, j);
}
}
}

希尔排序

希尔排序是一种基于插入排序的快速排序算法。
对于大规模的乱序排序算法,插入排序会很慢,因为它只会交换相邻的元素,因此元素只能一点点地从数组的一端移动到另一端。希尔排序为了加快排序,交换不相邻的元素对数组局部进行排序,并最终用插入排序将局部有序的数组排序。
特点:对于中等大小的数组运行时间可接受。它的代码量小,且不需要额外的内存空间。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static void shellSort(double[] A){
int N = A.length;
int h = 1;
while(h < N/3){
h = 3 * h + 1;
}
while(h >= 1){
for(int i = h; i < N; ++i){
for(int j = i; j >= h && compareTo(A[j-h], A[j]) == 1; j -= h)
exchange(A, j-h, j);
}
h = h / 3;
}
}

归并排序

将一个数组排序,可以先(递归地)将它分成两半分别排序,然后将结果归并起来。
优点:它能够保证将任意长度为N的数组排序所需的时间和NlogN成正比;
缺点:所需额外的辅助空间和N成正比。

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
private static double[] aux;
public static void mergeSort(double[] A){
aux = new double[A.length];
mergeSortAPI(A, 0, A.length-1);
}
//进行分割数组操作
private static void mergeSortAPI(double[] A, int lo, int hi){
if(lo >= hi){
return;
//可以设置当lo + x >= hi时,使用插入排序,减少递归带来的性能损耗
}
int mid = lo + (hi - lo) / 2;
mergeSortAPI(A, lo, mid);
mergeSortAPI(A, mid+1, hi);
merge(A, lo, mid, hi);
}
private static void merge(double[] A, int lo, int mid, int hi){
for(int k = lo; k <= hi; ++k){
aux[k] = A[k];
}
int i = lo;
int j = mid+1;
for(int k = lo; k <= hi; ++k){
if(i > mid){
A[k] = aux[j++];
}
else if(j > hi){
A[k] = aux[i++];
}
else if(compareTo(aux[i], aux[j]) == -1){
A[k] = aux[i++];
}
else{
A[k] = aux[j++];
}
}
}

快速排序

快速排序是一种分治的排序算法。它将一个数组分成两个子数组,将两部分独立地排序。快速排序和归并排序是互补的:归并排序将数组分成两个子数组分别排序,并将有序的子数组归并以将整个数组排序;快速排序则是当两个数组都有序时,整个数组也自然就有序了。

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
public static void quickSort(double[] A){
quickSortAPI(A, 0, A.length-1);
}
private static void quickSortAPI(double[] A, int lo, int hi){
if(lo >= hi){
//这里可以使用插入排序,降低递归带来的效率下降
//判断条件应该是 lo + x >= hi
return;
}
int pivot = partition(A, lo, hi);
quickSortAPI(A, lo, pivot-1);
quickSortAPI(A, pivot+1, hi);
}
private static int partition(double[] A, int lo, int hi){
int pivot = lo;
int i = lo;
int j = hi+1;
for( ; ; ){
//这里的边界条件是i < hi, 如果当i == hi时
//在进行下次循环的时候访问的A[hi+1]就会越界
while(compareTo(A[++i], A[pivot]) == -1 && i < hi){}
while(compareTo(A[pivot], A[--j]) == -1 && j > lo){}
//这里的边界条件是相同的道理,如果 i == j == hi 时候未跳出
//在for循环的第一次while的A[hi+1]就会越界
if(i >= j){
break;
}
exchange(A, i, j);
}
exchange(A, pivot, j);
//pivot记得放在正确的位置
//A[lo, j-1] <= A[j] <= A[j+1, hi] 成立
return j;
}

三向切分的快速排序

优点:三向切分的快速排序比归并排序、标准快速排序和其他排序方法在包括重复元素很多的实际应用中更快。

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
public static void quickThreeWaySort(double[] A){
quickThreeWay(A, 0, A.length-1);
}
private static void quickThreeWay(double[] A, int lo, int hi){
if(lo >= hi){
//同上
return;
}
double pivot = A[lo];
int lt = lo; //小于pivot的指针
int i = lo + 1; //等于pivot的指针
int gt = hi; //大于pivot的指针
while(i <= gt){
int cmp = compareTo(A[i], pivot);
if(cmp < 0){
exchange(A, i++, lt++);
}
else if(cmp > 0){
exchange(A, i, gt--);
}
else{
i++;
}
}
//跳出while循环后
//A[lo, lt-1] < pivot=A[lt, gt] < A[gt+1, hi]成立
quickThreeWay(A, lo, lt-1);
quickThreeWay(A, gt+1, hi);
}
public static void quickSort(double[] A){
quickSortAPI(A, 0, A.length-1);
}
private static void quickSortAPI(double[] A, int lo, int hi){
if(lo >= hi){
//这里可以使用插入排序,降低递归带来的效率下降
//判断条件应该是 lo + x >= hi
return;
}
int pivot = partition(A, lo, hi);
quickSortAPI(A, lo, pivot-1);
quickSortAPI(A, pivot+1, hi);
}

冒泡排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static void bubbleSort(int []A){
int N = A.length;
for(int i = 0; i < N; ++i){
boolean isSequence = true;
for(int j = N-1; j > i; --j){
if(Util.compareTo(A, j-1, j) == 1){
Util.exchange(A, j-1, j);
isSequence = false;
}
}
if(isSequence){
break;
}
}
}

堆排序

从零开始的Servlet(2)

发表于 2017-09-20

Servlet

MVC模型

Java Web的Model2开发模型就是MVC思想的体现。

Servlet练手小项目

使用Servlet技术实现购物车效果

从零开始的Servlet(1)

发表于 2017-09-19 | 分类于 Java

Servlet基础

Servlet是JSP的前身。Servlet是在服务端上运行的小程序,一个Servlet就是一个Java类,并且可以通过“请求–响应”编程模型来访问的这个驻留在服务器内存里的Servlet程序。

Tomcat容器等级

Tomcat的容器分为四个等级:
Servlet的容器管理Context容器,一个Context对应于一个web工程

创建Servlet

Servelet的继承体系如下:
自定义Servlet –> Abstract class HttpServlet –> Abstract class GenericServlet –> interface Servlet

写个小例子

  1. 继承HttpServlet
  2. 重写doGet()和doPost()方法
  3. 在web.xml中注册Servlet

这个方式和Django里的View.py里处理request和response的方式有点像。

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
package com.servlet.ackerman;
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{
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// super.doGet(request, response);
System.out.println("处理Get()请求");
PrintWriter out = response.getWriter();
response.setContentType("text/html;charset=utf-8");
out.println("<Strong>Hello World</Strong>");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// super.doPost(req, resp);
System.out.println("处理Post()请求");
PrintWriter out = response.getWriter();
response.setContentType("text/html;charset=utf-8");
out.println("<Strong>Hello MyBaby</Strong>");
}
}

接着在web.xml注册HelloServlet类,就像在Django的admin.py里注册一样

1
2
3
4
5
6
7
8
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>com.servlet.ackerman.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/HelloServlet</url-pattern>
</servlet-mapping>

在页面上使用Servlet,注意这里的href和action的链接与上面的url-pattern要匹配

1
2
3
4
5
<h1>第一个Servlet例子</h1>
<a href="HelloServlet">Get方式请求HelloServlet</a>
<form action="HelloServlet" method="POST">
<input type="submit" value="Post方式提交HelloServlet"/>
</form>

Servlet的执行流程

Get方式请求HelloServlet –> <\a href=”appNames/HelloServlet”> –> 在web.xml寻找对应的url-pattern –> 在web.xml寻找对应的servlet-class –> 寻找HelloServlet类中的doGet()请求方法

HttpServlet类扩展了GenericServlet类,实现了GenericServlet类的抽象方法。
HttpServlet类有两个service()方法。
我们自己编写的Servlet继承了HttpServlet类,一般只需覆盖doPost或者doGet方法,不必覆盖service方法,因为service()会调用doPost或者doGet方法。

Servlet生命周期

三个阶段:

  1. 初始化阶段,Servlet类先被创建,然后调用init()方法(如果Servlet已经被加载,直接进行第二步)。
  2. 响应客户请求阶段,调用service()方法。由service()方法根据提交方式选择执行doGet()或者doPost()方法。
  3. 终止阶段,调用destroy方法。

servlet加载的三种情况

首先要记得Servlet实例化对象是长期存放在内存中的。
在下列时刻Servlet容器装载Servlet:

  1. Servlet容器启动时自动装载某些Servlet,实现它只需要在web.xml文件中Servlet标签中添加如下代码,数字越小表示优先级越高。

    1
    <loadon-startup>1</loadon-startup>

    这样启动Tomcat容器后Servlet类会被创建并调用init()方法。

  2. 在Servlet容器启动后,客户首次向Servlet发送请求。
  3. Servlet类文件被更新后,重新加载Servlet。

Servlet被加载后,Servlet容器创建一个Servlet实例并且调用Servlet的init()方法进行初始化。在整个Servlet的整个生命周期内,init()方法只被调用一次。

Servlet和JSP内置对象

下面展示的是JSP九大内置对象怎么在Servlet中获得

1
2
3
4
5
6
7
8
9
out resp.getWriter
request service()方法中的req参数
response service()方法中的resp参数
session req.getSession函数
application getServletContext()函数
exception Throwable
page this
pageContext PageContext
Config getServletConfig()函数

Servlet 路径跳转

Servlet 获取初始化参数

第一步:
写JSP页面

1
2
<h1>获取初始化参数</h1>
<a href="GetInitParameterServlet">点我点我</a>

第二步:
写Servlet类:

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
57
package com.servlet;
import com.sun.deploy.net.HttpResponse;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.ws.http.HTTPException;
import java.io.IOException;
import java.io.PrintWriter;
public class GetInitParameterServlet extends HttpServlet {
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
//在初始化Servlet类的时候会调用该函数
//获取在web.xml中的参数
public void init() throws ServletException{
this.setUsername(this.getInitParameter("username"));
this.setPassword(this.getInitParameter("password"));
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws HTTPException, IOException{
doPost(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws HTTPException, IOException{
//将获得的初始化参数返回在页面
response.setContentType("text/html;charset=utf-8");
PrintWriter outer = response.getWriter();
outer.println(this.getUsername() + "<br/>");
outer.println(this.getPassword() );
}
}

第三步:
在web.xml中注册Servlet类并设置初始参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<servlet>
<servlet-name>InitParameter</servlet-name>
<servlet-class>com.servlet.GetInitParameterServlet</servlet-class>
<init-param>
<param-name>username</param-name>
<param-value>ackerman</param-value>
</init-param>
<init-param>
<param-name>password</param-name>
<param-value>javaweb</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>InitParameter</servlet-name>
<url-pattern>/GetInitParameterServlet</url-pattern>
</servlet-mapping>

从零开始的JDBC(1)

发表于 2017-09-19 | 分类于 Java

JDBC入门

使用IDEA连接JDBC

准备:到MySQL官网下载JDBC驱动

  1. 新建Java工程 View –> Tool Windows –> Database –> 添加DataSource –> MySQL
  2. 填写参数:
    Host:localhost
    DataBase:数据库名称
    User:root
    Password:xxxooo
  3. 点击Test Connection 测试是否成功,否则按照提示解决
  4. File –> Project Structure –> Modules –> Dependencies –> 添加刚刚卸载的mysql驱动
  5. 在工程目录下的External Libraries找到驱动就完成了

使用IDEA连接MySQL数据库

测试JDBC是否能够正常工作。

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
package cn.jdbc.one_piece;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
public class Operation {
private static final String URL = "jdbc:mysql://127.0.0.1/ackerman?useSSL=false";
private static final String USER = "root";
private static final String PASSWORD = "ljj5588006";
public static void main(String[] args) throws Exception{
//加载MySQL驱动
Class.forName("com.mysql.jdbc.Driver");
//连接到数据库
Connection conn = DriverManager.getConnection(URL, USER, PASSWORD);
//测试是否成功,并查询数据
Statement stat = conn.createStatement();
ResultSet rs = stat.executeQuery("SELECT name, age FROM person");
while(rs.next()){
System.out.println(rs.getString("name") + ": " + rs.getInt("age"));
}
}
}

JDBC实例

JDBC说白了就是在Java程序中调用一些API使用SQL语句。

从零开始的JSP(5)

发表于 2017-09-18 | 分类于 Java

指令与动作

include指令

作用是与Django里的模板语言include一样的,显示被包含页面的内容
语法:

1
<%@ include file="URL" %>

include动作

语法:

1
2
3
//page:要包含的页面
//flush:被包含的页面是否从缓冲区读取
<jsp:include page="url" flush="false" />

include指令和动作的区别

除了语法格式的不同,指令和动作还有区别如下:

  1. 发生作用的时间:include指令发生在编译页面期间,include动作发生在请求期间
  2. 包含的内容:include指令为文件的实际内容,include动作为页面的输出
  3. 转换成Servlet:主页面和包含页面转换为一个Servlet,主页面和包含页面转换为独立的Servlet
  4. 编译时间:include指令需要解析资源较慢,include动作较快
  5. 执行时间:include指令快,includ动作每次需要解析资源较慢

forward动作

语法:

1
<jsp:forward page="URL" />

等同于

1
2
//服务器转发语句
request.getRequestDispatcher("url").forward(reqeust, response)

param动作

语法:

1
2
//常常与<jsp:forward>一起使用,作为其的子标签
<jsp:param name="参数名" value="参数值">

举个例子:

1
2
3
<jsp:forward page="another.jsp">
<jsp:param name="address" value="ttliujj@gmail.com">
</jsp:forward>

从零开始的JSP(4)

发表于 2017-09-18 | 分类于 Java

JSP状态管理

HTTP协议的无状态性

无状态是指,当浏览器发送请求给服务器的时候,服务器响应客户端的请求。但是当同一个浏览器再次发送请求给服务器的时候,服务器并不知道它就是刚刚的那个浏览器。
简单的说,服务器不会记住哪个浏览器访问过自己,所以称为无状态协议。

保存用户状态的两个机制

服务端技术:Session
客户端技术:Cookie

Cookie:Web服务器保存在客户端的一系列文本信息。
典型用法:判断注册用户是否登录网站,信息的相关推荐和记住用户名(xx天内免登录)

JSP创建与使用Cookie

创建Cookie对象

1
Cookie cookie = new Cookie(String Key, Object obj);

写入Cookie对象

1
response.addCookie(cookie)

读取Cookie对象

1
Cookie [] cookiesp = request.getCookies()

Cookie对象的常用方法

  1. void setMaxAge(int expiry) 设置Cookie的有效期,秒/单位
  2. int getMaxAge() 获取Cookie的有效时间
  3. void setValue(String value) 在Cookie创建后,对Cookie进行赋值
  4. String getName() 获取Cookie的名称
  5. String getValue() 获取Cookie的值

使用Cookie实现登录

这个实例使用了三个jsp页面,分别是登录页面login.jsp、处理登录页面dologin.jsp和显示用户信息users.jsp。

login.jsp页面,脚本语言里实现的是如果上次有保存用户名和密码的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
<%
String username="";
String password="";
Cookie[] cookies = request.getCookies();
if(cookies != null && cookies.length > 0){
for(Cookie c : cookies){
if(c.getName().equals("username")){
username = c.getValue();
}
if(c.getName().equals("password")){
password = c.getValue();
}
}
}
%>
<h1>用户登录页面</h1>
<form name="loginForm" action="dologin.jsp" method="post">
<table>
<tr>
<td>用户:</td>
<td><input type="text" name="username" value=<%= username %>></td>
</tr>
<tr>
<td>密码:</td>
<td><input tyepe="text" name="password" value=<%= password %>></td>
</tr>
<tr>
<td colspan="2"><input type="checkbox" name="isUseCookie">十天内免登陆</td>
</tr>
<tr>
<td colspan="3"><input type="submit"></td>
</tr>
</table>
</form>

处理登录页面dologin.jsp

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
<%
String [] isUseCookies = request.getParameterValues("isUseCookie");
//首先判断是否是点击保存Cookie
//如果点击是,那么就要把该用户名和密码保存下来
if(isUseCookies != null && isUseCookies.length > 0){
//通过request请求获取username和password
String username = request.getParameter("username");
String password = request.getParameter("password");
//分别创建username和password的Cookie值
Cookie newUsernameCookie = new Cookie("username", username);
Cookie newPasswordCookie = new Cookie("password", password);
//设置保存时间为10天
newUsernameCookie.setMaxAge(864000);
newPasswordCookie.setMaxAge(864000);
//Cookie信息入库
response.addCookie(newUsernameCookie);
response.addCookie(newPasswordCookie);
}
else{
//如果未点击保存Cookie,需要将已保存的Cookie值给删除
//当然,这只处理username和password的值
Cookie[] cookies = request.getCookies();
if(cookies!=null && cookies.length > 0){
for(Cookie c : cookies){
if(c.getName().equals("username") || c.getName().equals("password")){
c.setMaxAge(0);
response.addCookie(c);
}
}
}
}
%>
<a href="users.jsp" target="_blank">查看用户信息</a>

如果点击了有相应的Cookie被保存,那么就可以查看到我们的用户名和密码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<%
String username="";
String password="";
Cookie[] cookies = request.getCookies();
if(cookies != null && cookies.length > 0){
for(Cookie c : cookies){
if(c.getName().equals("username")){
username = c.getValue();
}
if(c.getName().equals("password")){
password = c.getValue();
}
}
}
%>
<hr>
用户:<%= username %><br/>
密码:<%= password %><br/>

Session和Cookie的对比

共同点:用来保存用户的状态信息且都会过期
不同点:

  1. Session在服务端内存中保存用户信息,Cookie以文本形式保存在客户端
  2. Session保存在Object类型,Cookie保存的是String类型
  3. Session随会话的结束而将其存储的数据销毁,Cookie可以长期保存在客户端
  4. Session安全性较高,保存重要的信息,Cookie保存不重要的用户信息

从零开始的JSP(3)

发表于 2017-09-18 | 分类于 Java

JavaBean

JavaBean简介

JavaBean就是符合某种特定的规范的Java类,使用JavaBean的好处是解决代码的重复编写,减少代码冗余,功能区分明确,提高了代码的维护性。

JavaBean的设计原则
包含以下4点:

  1. 公有类
  2. 无参数的公有构造函数
  3. getter和setter函数
  4. 私有属性域
1
2
3
4
5
6
7
8
public class Students{
public Students(){
}
public void setName(String name){this.name=name;}
public String getName() {return name;}
private String name;
}

JSP动作元素
JSP动作元素为请求处理阶段提供信息。动作元素遵循XML元素的语法,有一个包含元素名的开始标签,可以有属性、可选内容、与开始标签匹配的结束标签。

JavaBean的使用

普通方法

如上面的Students知道创建JavaBean类的就像普通的Java类一样(在设计规范的规定下)。

1
2
3
4
5
6
7
8
9
<%@ page import="com.ackerman.Students"%>
<h1>使用普通方法创建JavaBean的实例</h1>
<%
Students stupid = new Students();
stupid.setName("Ackerman");
%>
输出效果:<%= stupid.getName() %><br/>

JSP动作标签方法

< jsp:useBean >:在JSP页面中实例化JavaBean对象

1
<jsp:useBean id="标示符" class="java包和类名" scope="作用范围">

####:在给已经实例化的JavaBean对象的属性赋值,一共有四中方式

1
2
3
4
5
6
7
<jsp:setProperty name="JavaBean实例名" property="*">(与表单关联)
<jsp:setProperty name="JavaBean实例名" property="具体的属性名">(与表单关联)
<jsp:setProperty name="student1" property="name" value="yoyocheckenow"/>(手工设置)
<jsp:setProperty name="student1" property="name" param="传递的参数"/>(与request请求的数据有关)

下面是用法展示:
先写一个登录login.jsp的页面

1
2
3
4
5
6
7
8
9
10
11
<form action="dologin.jsp" name="loginForm" method="post">
<table>
<tr>
<td>用户名:</td>
<td><input type="text" name="name"/></td>
</tr>
<tr>
<td colspan="2"><input type="submit"></td>
</tr>
</table>
</form>

将login.jsp的参数传递到dologin.jsp页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//实例化Students对象
<jsp:useBean id="student1" class="com.ackerman.Students" scope="page"/>
<h1>setProperty动作元素使用方法</h1>
//第一种方法:根据表单匹配所有的属性
//login.jsp表单的name="name"属性值要与Students中的name私有域保持一致
<jsp:setProperty name="student1" property="*"/>
//第二种方法:根据表单匹配对象的属性
<jsp:setProperty name="student1" property="name"/>
//第三种方法:设置Students私有域name的值为yoyochecknow
<jsp:setProperty name="student1" property="name" value="yoyocheckenow"/>
//第四种方法:通过URL传参数
//在login.jsp做如下的修改:
//<form action="dologin.jsp?ff=hello" name="loginForm" method="post">
//这样就可以将URL传递的ff属性值赋值给Students的私有域name
<jsp:setProperty name="student1" property="name" param="ff"/>
得到的name属性值:<%= student1.getName() %>

< jsp:getProperty >:获取制定JavaBean对象的属性值

1
<jsp:getProperty name="JavaBean实例名" property="属性名">

修改dologin.jsp中的代码,获取JavaBean对象的属性值

1
得到的name属性值:<jsp:getProperty name="student1" property="name">

JavaBean的四个作用域范围

说明:使用useBean的scope属性可以用来指定JavaBean的作用范围。

  1. page 默认值,仅在当前页面有效
  2. request 可以通过HttpReqeust.getAttribute()方法取得JavaBean对象
  3. session 可以通过HttpSession.getAttribute()方法取得JavaBean对象
  4. application 可以通过application.getAttribute()方法取得JavaBean对象
1
<jsp:useBean id="student1" class="com.ackerman.Students" scope="作用域范围">
1…101112
塔头刘德华

塔头刘德华

113 日志
11 分类
8 标签
© 2018 塔头刘德华
由 Hexo 强力驱动
|
主题 — NexT.Pisces v5.1.2