2011年11月25日
下载的docker镜像默认存储路径是/var/lib/docker .具体的镜像文件就在containers文件夹中
docker save -o d:/docker/zen.tar easysoft/zentao:15.5
docker run -d -p 80:80 \
-e ADMINER_USER="admin" -e ADMINER_PASSWD="qqzj126" -e MYSQL_ROOT_PASSWORD=qqzj126 \
-e BIND_ADDRESS="false" \
-v /opt/data/zbox/:/opt/zbox/ \
-v /opt/mysqldata:/var/lib/mysql \
--name zentao-server \
easysoft/zentao:15.5
docker logs -f
运行命令(注意路径)
java -jar /web/share-book.jar > /web/log.txt &
该命令的意思是:执行share-book.jar这个文件,并且输出到log.txt文件,&表示后台运行
解决更新项目带来的频繁重启操作,创建2个脚本
start.sh
#! /bin/bash
#注意:必须有&让其后台执行,否则没有pid生成 jar包路径为绝对路径
java -jar /web/share-book.jar > /web/log.txt &
# 将jar包启动对应的pid写入文件中,为停止时提供pid
echo $! > /web/pid.txt
stop.sh
#! /bin/bash
PID=$(cat /web/pid.txt)
kill -9 $PID
启动项目:./start.sh
停止项目:./stop.sh
一.问题描述:windows本地调试Hadoop程序时报错错误信息:
其原因是需要在windows本地搭建Hadoop环境,下载winutils文件,并将hadoop-2.8.4包内的bin文件替换,将下载文件中hadoop.dll放到C:\Windows\System32下
二.解决过程如下:
1.下载hadoop,去官网下载对应的hadoop版本,我在linux集群搭建的是hadoop-2.8.4,因此将hadoop-2.8.4下载到windows本地
https://www.jianshu.com/p/a65a95108620
如果不配置.gitignore的文件,带push代码的时候就会把一写不必要的文件push到远程仓库,如.idea文件。如果不小心出现此文件在远程仓库可以通过一下步骤delete此文件:
1.配置.gitignore文件(新建/编辑)
echo '.idea' >> .gitignore
2.将.gitignore文件上传到远程仓库
git pull git add .gitignore git commit -m 'edit .gitignore' git push origin master
3.删除git的.idea文件
git rm --cached -r .idea
4.同步到远程仓库
git commit -m 'delete .idea' git push origin master
完成之后就可以发现git仓库中的.idea文件已经被删除,而且之后push代码也不会再把.idea文件上传。
PS:我在使用PyCharm编写python代码,一般是通过new -> .ignore file -> .gitignore file
自动生成.gitignore文件。
下面是我自己比较常用的.gitignore文件简短配置:
.project .settings/ .prefs .pydevproject .idea/ .idea .DS_Store .cache *.pyc *.html *.xlm
1、java heap space 一次申请太大的内存空间
2、GC overhead limit exceeded 创建太多的对象,gc收集不完
1、 vim /etc/rc.d/rc.local
2、添加内容
export JAVA_HOME=/usr/java/jdk1.8.0_111
/app/tomcat/bin/startup.sh start
3、
chmod 777 /etc/rc.d/rc.local
/**
* synchronized 放在普通方法上,内置锁就是当前类的实例
* @return
*/
public synchronized int getNext() {
return value ++;
}
/**
* 修饰静态方法,内置锁是当前的Class字节码对象
* Sequence.class
* @return
*/
public static synchronized int getPrevious() {
// return value --;
return 0;
}
1、数据库配置
首先使用canal需要修改数据库配置
[mysqld]
log-bin=mysql-bin # 开启
binlog binlog-format=ROW # 选择 ROW 模式
server_id=1 # 配置 MySQL replaction 需要定义,不要和 canal 的 slaveId 重复
创建canal数据库用户
CREATE USER canal IDENTIFIED BY 'canal';
GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'canal'@'%';
FLUSH PRIVILEGES;
2、安装canal
下载:https://github.com/alibaba/canal/releases
解压(修改版本号):tar zxvf canal.deployer-1.1.4.tar.gz -C ./canal
配置开放服务器端口:11110、11111、11112
修改canal配置文件(这里设置了两个instance,即两个数据库):
vi canal/conf/canal.properties
canal.destinations = example1,example2
配置instance:
cp -R canal/conf/example conf/example1
mv conf/example conf/example2
第一个数据库配置
vi canal/conf/example1/instance.properties
canal.instance.master.address=32.1.2.140:3306
第二个数据库配置
vi canal/conf/example2/instance.properties
canal.instance.master.address=32.1.2.140:3307
#如果需要新增一个instance,只需要修改canal.properties文件,并新增一个instance配置即可,无需重启canal。
运行:
sh canal/bin/startup.sh # 查看日志
cat canal/logs/canal/canal
3、Java使用样例
引入pom依赖,需要与安装的canal版本一致
<dependencies> <dependency> <groupId>com.alibaba.otter</groupId> <artifactId>canal.client</artifactId> <version>1.1.4</version> </dependency> </dependencies>
示例代码(异步打印两个数据库的修改内容):
package cn.spicybar.dblog; import com.alibaba.otter.canal.client.CanalConnector; import com.alibaba.otter.canal.client.CanalConnectors; import com.alibaba.otter.canal.protocol.CanalEntry.Entry; import com.alibaba.otter.canal.protocol.CanalEntry.EntryType; import com.alibaba.otter.canal.protocol.CanalEntry.RowChange; import com.alibaba.otter.canal.protocol.Message; import java.net.InetSocketAddress; import java.util.List; public class CanalClient { public static void main(String[] args) { new Thread(() -> initConnector("example1")).start(); new Thread(() -> initConnector("example2")).start(); } private static void initConnector(String destination) { CanalConnector connector = CanalConnectors.newSingleConnector(new InetSocketAddress("32.1.0.237", 11111), destination, "", ""); try { connector.connect(); connector.subscribe(".*\\..*"); connector.rollback(); while (true) { Message message = connector.getWithoutAck(1000); if (message.getId() != -1 && message.getEntries().size() > 0) { printEntry(message.getEntries()); } connector.ack(message.getId()); } } finally { connector.disconnect(); } } private static void printEntry(List<Entry> entries) { for (Entry entry : entries) { if (entry.getEntryType() == EntryType.TRANSACTIONBEGIN || entry.getEntryType() == EntryType.TRANSACTIONEND) { continue; } try { RowChange rowChange = RowChange.parseFrom(entry.getStoreValue()); System.out.println(rowChange.getSql()); } catch (Exception e) { throw new RuntimeException("ERROR ## parser error, data:" + entry.toString(), e); } } }
public int binarySearch(long value) {
int middle = 0;
int low = 0;
int pow = arr.length;
while(true) {
middle = (pow + low) / 2;
if(arr[middle] == value) {
return middle;
} else if(low > pow) {
return -1;
} else {
if(arr[middle] > value) {
pow = middle - 1;
} else {
low = middle + 1;
}
}
}
}
1.首先先把下载的压缩包解压到一个文件夹中
2.打开cmd指令窗口3.输入你刚才解压的文件路径4.然后输入redis-server redis.windows.conf 命令
接下来部署Redis为windows下的服务 首先关掉上一个窗口再打开一个新的cmd命令窗口
然后输入指令redis-server --service-install redis.windows.conf
随后,进入右击此电脑–管理–服务和应用程序–服务 启动服务
Redis常用的指令
卸载服务:redis-server --service-uninstall
开启服务:redis-server --service-start
停止服务:redis-server --service-stop
测试redis,通过cd到我们解压的目录,输入指令通过Set get指令查看是否成功
检查配置文件/canal.deployer-1.1.1/conf/canal.properties
canal.instance.tsdb.spring.xml=classpath:spring/tsdb/h2-tsdb.xml
以及
# table meta tsdb info
canal.instance.tsdb.enable=true
canal.instance.tsdb.dir=${canal.file.data.dir:../conf}/${canal.instance.destination:}
canal.instance.tsdb.url=jdbc:h2:${canal.instance.tsdb.dir}/h2;CACHE_SIZE=1000;MODE=MYSQL;
canal.instance.tsdb.dbUsername=canal
canal.instance.tsdb.dbPassword=canal
检查 tsdb是否已经开启
如果都已开启还是有这个问题 则需要清除canal对表结构的缓存
conf/example/h2.mv.db
问题2:找不到binlog日志文件
清空缓存
canal.deployer-1.1.1/conf/example/meta.dat
常规的windows操作
- 根目录下创建gitignore.txt;
- 编辑gitignore.txt,写下你的规则,例如加上node_modules/;
- 打开命令行窗口,切换到根目录(可以直接在文件夹上面的地址栏输入cmd回车);
- 执行命令ren gitignore.txt .gitignore。
在.gitignore中已经声明了忽略路径也是不起作用的,
这时候我们就应该先把本地缓存删除,然后再进行git的提交,这样就不会出现忽略的文件了。
解决方法: git清除本地缓存(改变成未track状态),然后再提交:
[root@kevin ~]
# git rm -r --cached .
[root@kevin ~]
# git add .
[root@kevin ~]
# git commit -m 'update .gitignore'
[root@kevin ~]
# git push -u origin master
安装k8s
systemctl disable firewalld
systemctl stop firewalld
yum update
yum install -y etcd kubernetes
vim /etc/kubernetes/apiserver
KUBE_ADMISSION_CONTROL改为下面的值
KUBE_ADMISSION_CONTROL="--admission-control=NamespaceLifecycle,NamespaceExists,LimitRange
vi /etc/kubernetes/manifests/kube-apiserver.yaml
--service-node-port-range: 1-65535
systemctl start etcd
systemctl start docker
如果启动docker 失败,修改 /etc/sysconfig/selinux
把 selinux后面改成 disabled , 重启机器,reboot -n 再启动docker就好了
systemctl start kube-apiserver
systemctl start kube-controller-manager
systemctl start kube-scheduler
systemctl start kubelet
systemctl start kube-proxy
kubectl create -f mytomcat-rc.yaml
clean package docker:build -DpushImage
1.使用DockerMaven,可以实现我们项目一键式部署,简便操作流程。
Maven插件自动部署步骤:
a.首先我们要设置docker的宿主机开启权限.
修改宿主机的docker配置,让其可以远程访问 vi /lib/systemd/system/docker.service
其中ExecStart=后添加配置 -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock
b.刷新配置,重启服务
systemctl daemon-reload
systemctl restart docker
docker start registry
c.在工程pom.xml 增加配置
<build>
<finalName>app</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<!-- docker的maven插件,官网:https://github.com/spotify/docker-maven-plugin
-->
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>0.4.13</version>
<configuration>
<imageName>192.168.184.141:5000/${project.artifactId}:${project.version}
</imageName>
<baseImage>jdk1.8</baseImage>
<entryPoint>["java", "-jar", "/${project.build.finalName}.jar"]
</entryPoint>
<resources>
<resource>
<targetPath>/</targetPath>
<directory>${project.build.directory}</directory>
<include>${project.build.finalName}.jar</include>
</resource>
</resources>
<dockerHost>http://192.168.184.141:2375</dockerHost>
</configuration>
</plugin>
</plugins>
</build>
create table SAP_E_DSOQQZT_TMP
(
id NUMBER not null,
request NUMBER,
)
tablespace USERS
pctfree 10
initrans 1
maxtrans 255
storage
(
initial 16K
next 8K
minextents 1
maxextents unlimited
)
partition by range(request) interval(1000000)
(
partition SAP_E_DSOQQZT_part values less than(700000000)
);
-- Add comments to the columns
comment on column SAP_E_DSOQQZT_TMP.id
is 'ID';
comment on column SAP_E_DSOQQZT_TMP.request
is '请求号';
-- Create/Recreate indexes
create index FCREATETIMEA on SAP_E_DSOQQZT_TMP ( REQUEST)
tablespace ZHFXBEMS
pctfree 10
initrans 2
maxtrans 255
storage
(
initial 1847M
next 1M
minextents 1
maxextents unlimited
);
-- Create/Recreate primary, unique and foreign key constraints
alter table SAP_E_DSOQQZT_TMP
add constraint PK_SAP_E_DSOQQZTA primary key (ID)
using index
tablespace USERS
pctfree 10
initrans 2
maxtrans 255
storage
(
initial 112M
next 1M
minextents 1
maxextents unlimited
);
第二步:判断表是否可以在线从新定义
begin
dbms_redefinition.can_redef_table('ERPSU','SAP_E_DSOQQZT',DBMS_REDEFINITION.CONS_USE_PK);
end;
第三步:开始执行数据的迁移(30分钟)
begin
DBMS_REDEFINITION.START_REDEF_TABLE('ERPSU','SAP_E_DSOQQZT', 'SAP_E_DSOQQZT_TMP');
end;
第四步:进行权限对象的迁移
DECLARE
num_errors PLS_INTEGER;
BEGIN
DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS('ERPSU','SAP_E_DSOQQZT', 'SAP_E_DSOQQZT_TMP',
DBMS_REDEFINITION.CONS_ORIG_PARAMS, TRUE, TRUE, TRUE, TRUE, num_errors);
END;
第五步:结束整个重定义
BEGIN
DBMS_REDEFINITION.FINISH_REDEF_TABLE('ERPSU','SAP_E_DSOQQZT', 'SAP_E_DSOQQZT_TMP');
END;
第六步,删除临时表 SAP_E_DSOQQZT_TMP
万一哪一步出错,执行:
BEGIN
DBMS_REDEFINITION.ABORT_REDEF_TABLE(uname => 'ERPSU',
orig_table => 'SAP_E_DSOQQZT',
int_table => 'SAP_E_DSOQQZT_TMP'
);
END;
-----------------------------------------------------------------------------
删除所有的docker镜像
docker rmi `docker images -q` (`符号是esc下面的按键)
交互式方式创建容器
docker run -it --name=容器名称 镜像名称:标签 /bin/bash
进入守护式的容器
docker exec -it 容器名称 /bin/bash
-i 表示运行容器
-t 表示容器启动后进入容器命令行,容器创建后可以登录进去
--name 给容器命名
-v 表示目录映射关系(前者是宿主机目录,后者是容器目录),可以用多个-v做多个目录或者文件映射,最好做目录映射,在宿主机上做修改,然后共享到容器上。
-d 创建一个守护容器在后台运行,如果只加-i-t,创建后会自动进去容器。
-p 表示端口映射,前者是宿主机端口,后者是容器内的端口,可以多个端口映射
docker stop 容器id (停止容器)
docker start 容器id (停止容器)
向容器内复制文件
docker cp 需要复制的文件目录 容器:容器内的目录
从容器内复制文件
docker cp 容器:容器内的目录 需要复制的文件目录
1、yum包更新到最新
sudo yum update
2 、安装需要的软件包
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
3、设置yum源为阿里云
sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
4、 安装docker
sudo yum install docker-ce
5、查看版本
docker -v
6、修改镜像下载源
vi /etc/docker/daemon.json
写入:
{
"registry-mirrors": ["http://docker.mirrors.ustc.edu.cn"]
}
7、启动docker
systemctl start docker
8、docker 开机自动启动
systemctl enable docker
编写完Dockerfile,执行构建命令
docker build -t 192.168.1.9:5000/admin-service .
docker run -p 8888:8888 192.168.1.9:5000/admin-service
1、在分布上系统环境下,一个方法在同一时间只能被一个机器上的一个线程访问
2、高可用的获取锁和释放锁
3、高效的获取锁和释放锁
4、具备可重入特性(重新进入,由多个任务并发使用,不比担心数据错误)
5、具备锁的失效机制,防止死锁
6、具备非阻塞锁的特性,没有获取到锁,直接返回获取锁失败
1。新建/usr/local/docker/registry 文件夹
2、在registry中新建docker-compose.yml文件,编辑此文件
version: '3.1'
services:
registry:
image: registry:2.7.1
restart: always
container_name: registry
ports:
- 5000:5000
volumes:
- /usr/local/docker/registry/data:/var/lib/registry
frontend:
image: konradkleine/docker-registry-frontend:v2
ports:
- 8080:80
volumes:
- ./certs/frontend.crt:/etc/apache2/server.crt:ro
- ./certs/frontend.key:/etc/apache2/server.key:ro
environment:
- ENV_DOCKER_REGISTRY_HOST=192.168.1.8
- ENV_DOCKER_REGISTRY_PORT=50003.运行 docker-compose up4.上传镜像docker tag tomcat 192.168.1.8:5000/tomcat:8.1
docker push 192.168.1.8:5000/tomcat:8.1
version: '3.1' services: mysql: restart: always image: mysql:5.7.22 container_name: mysql ports: - 3306:3306 environment: TZ: Asia/Shanghai MYSQL_ROOT_PASSWORD: 123456 command: --character-set-server=utf8mb4 --collation-server=utf8mb4_general_ci --explicit_defaults_for_timestamp=true --lower_case_table_names=1 --max_allowed_packet=128M --sql-mode="STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ERROR_FOR_DIVISION_BY_ZERO" volumes: - mysql-data:/var/lib/mysql volumes: mysql-data:
version: '3.1' services: db: image: mysql restart: always environment: MYSQL_ROOT_PASSWORD: 123456 command: --default-authentication-plugin=mysql_native_password --character-set-server=utf8mb4 --collation-server=utf8mb4_general_ci --explicit_defaults_for_timestamp=true --lower_case_table_names=1 ports: - 3306:3306 volumes: - ./data:/var/lib/mysql adminer: image: adminer restart: always ports: - 8080:8080
批量安装依赖包:rpm -Uvh *.rpm --nodeps --force
安装 container-selinux-2.9-4.el7.noarch.rpm
: rpm -Uvh container-selinux-2.9-4.el7.noarch.rpm
pasting
安装 docker
:rpm -Uvh docker-ce-18.03.1.ce-1.el7.centos.x86_64.rpm
pasting
- 启动docker:
systemctl start docker
- 查看
docker
启动容器列表: docker ps
select d.file_name,d.tablespace_name,d.autoextensible from dba_temp_files d;
select d.file_name,d.tablespace_name,d.autoextensible from DBA_DATA_FILES d;
drop tablespace tablespace_name including contents and datafiles;
ALTER TABLESPACE users ADD DATAFILE
'/app/oradata/orclnew/orclnew/users02.dbf'
size 7167M autoextend on ;
SELECT sid, serial#, username, osuser FROM v$session where sid in (select session_id from v$locked_object);
删除连接的session
ALTER SYSTEM KILL SESSION '9,4335';
导出oracle数据
exp xxx/xxx@orclnew file=/app/backup.dmp owner=xxx rows=n
当导出报错信息是 EXP-00091: Exporting questionable statistics时,执行下面的语句
select userenv('language') from dual;
export NLS_LANG=AMERICAN_AMERICA.ZHS16GBK
1、使用反编译工具找到需要修改的class文件,保存成Java文件。
2、新建Java项目,导入所有需要的jar,在src中放入需要修改的Java文件。
3、修改完毕后,在bin中找到新生成的class文件,解压原来的jar,替换class文件。
4.有三种方式重新打包,a 把解压替换过的jar文件导入到eclipse中,导出jar
b 使用zip压缩格式,修改后缀名jar
c 进入文件目录,使用
执行jar -cvf aa.jar
public interface Data {
String getResult();
}
public class FutureData implements Data{
protected Data data=null;
protected boolean f=false;
public synchronized void setData(Data data) {
if(f) {
return;
}
f=true;
this.data=data;
notifyAll();
}
@Override
public synchronized String getResult() {
while (!f) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return data.getResult();
}
}
public class RealData implements Data{
protected String s;
public RealData(String name) {
StringBuffer sb=new StringBuffer("");
for (int i = 0; i < 10; i++) {
sb.append(name);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
s=sb.toString();
}
@Override
public String getResult() {
// TODO Auto-generated method stub
return s;
}
}
public class Client {
public Data request(final String ss) {
final FutureData f=new FutureData();
new Thread() {
public void run() {
RealData r=new RealData(ss);//模拟复杂的数据封装和处理
f.setData(r);
};
}.start();
return f;
}
public static void main(String[] args) {
Client client=new Client();
Data d = client.request("123");
System.out.println(d.getResult());
}
}
public class FutureTest {
public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService e=Executors.newFixedThreadPool(11);
FutureTask<String> f=new FutureTask<>(new Callable<String>() {
@Override
public String call() throws Exception {
Thread.sleep(5000);
return "aa";
}
});
e.submit(f);
System.out.println(f.get());
}
}
vi clean.sh
logs_path="/appqqq/tomcat/logs"
find $logs_path -mtime +3 -name "localhost.*.log" -exec rm -rf {} \;
find $logs_path -mtime +3 -name "localhost_access_log.*.txt" -exec rm -rf {} \;
find $logs_path -mtime +3 -name "catalina.*.log" -exec rm -rf {} \;
find $logs_path -mtime +3 -name "manager.*.log" -exec rm -rf {} \;
find $logs_path -mtime +3 -name "host-manager.*.log" -exec rm -rf {} \;
find $logs_path -mtime +3 -name "fileservice.log.*" -exec rm -rf {} \;
>$logs_path/catalina.out;
chmod 777 clean.sh
crontab -e
0 2 * * * sh /appqqq/tomcat/logs/clean.sh
课程大纲
1、document数据格式
2、电商网站商品管理案例:背景介绍
3、简单的集群管理
4、商品的CRUD操作(document CRUD操作)
----------------------------------------------------------------------------------------------------------------------------
1、document数据格式
面向文档的搜索分析引擎
(1)应用系统的数据结构都是面向对象的,复杂的
(2)对象数据存储到数据库中,只能拆解开来,变为扁平的多张表,每次查询的时候还得还原回对象格式,相当麻烦
(3)ES是面向文档的,文档中存储的数据结构,与面向对象的数据结构是一样的,基于这种文档数据结构,es可以提供复杂的索引,全文检索,分析聚合等功能
(4)es的document用json数据格式来表达
2、电商网站商品管理案例背景介绍
有一个电商网站,需要为其基于ES构建一个后台系统,提供以下功能:
(1)对商品信息进行CRUD(增删改查)操作
(2)执行简单的结构化查询
(3)可以执行简单的全文检索,以及复杂的phrase(短语)检索
(4)对于全文检索的结果,可以进行高亮显示
(5)对数据进行简单的聚合分析
----------------------------------------------------------------------------------------------------------------------------
3、简单的集群管理
(1)快速检查集群的健康状况
es提供了一套api,叫做cat api,可以查看es中各种各样的数据
GET /_cat/health?v
epoch timestamp cluster status node.total node.data shards pri relo init unassign pending_tasks max_task_wait_time active_shards_percent
1488006741 15:12:21 elasticsearch yellow 1 1 1 1 0 0 1 0 - 50.0%
epoch timestamp cluster status node.total node.data shards pri relo init unassign pending_tasks max_task_wait_time active_shards_percent
1488007113 15:18:33 elasticsearch green 2 2 2 1 0 0 0 0 - 100.0%
epoch timestamp cluster status node.total node.data shards pri relo init unassign pending_tasks max_task_wait_time active_shards_percent
1488007216 15:20:16 elasticsearch yellow 1 1 1 1 0 0 1 0 - 50.0%
如何快速了解集群的健康状况?green、yellow、red?
green:每个索引的primary shard和replica shard都是active状态的
yellow:每个索引的primary shard都是active状态的,但是部分replica shard不是active状态,处于不可用的状态
red:不是所有索引的primary shard都是active状态的,部分索引有数据丢失了
为什么现在会处于一个yellow状态?
我们现在就一个笔记本电脑,就启动了一个es进程,相当于就只有一个node。现在es中有一个index,就是kibana自己内置建立的index。由于默认的配置是给每个index分配5个primary shard和5个replica shard,而且primary shard和replica shard不能在同一台机器上(为了容错)。现在kibana自己建立的index是1个primary shard和1个replica shard。当前就一个node,所以只有1个primary shard被分配了和启动了,但是一个replica shard没有第二台机器去启动。
做一个小实验:此时只要启动第二个es进程,就会在es集群中有2个node,然后那1个replica shard就会自动分配过去,然后cluster status就会变成green状态。
(2)快速查看集群中有哪些索引
GET /_cat/indices?v
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size
yellow open .kibana rUm9n9wMRQCCrRDEhqneBg 1 1 1 0 3.1kb 3.1kb
(3)简单的索引操作
创建索引:PUT /test_index?pretty
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size
yellow open test_index XmS9DTAtSkSZSwWhhGEKkQ 5 1 0 0 650b 650b
yellow open .kibana rUm9n9wMRQCCrRDEhqneBg 1 1 1 0 3.1kb 3.1kb
删除索引:DELETE /test_index?pretty
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size
yellow open .kibana rUm9n9wMRQCCrRDEhqneBg 1 1 1 0 3.1kb 3.1kb
----------------------------------------------------------------------------------------------------------------------------
4、商品的CRUD操作
(1)新增商品:新增文档,建立索引
PUT /index/type/id
{
"json数据"
}
PUT /ecommerce/product/1
{
"name" : "gaolujie yagao",
"desc" : "gaoxiao meibai",
"price" : 30,
"producer" : "gaolujie producer",
"tags": [ "meibai", "fangzhu" ]
}
{
"_index": "ecommerce",
"_type": "product",
"_id": "1",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"created": true
}
PUT /ecommerce/product/2
{
"name" : "jiajieshi yagao",
"desc" : "youxiao fangzhu",
"price" : 25,
"producer" : "jiajieshi producer",
"tags": [ "fangzhu" ]
}
PUT /ecommerce/product/3
{
"name" : "zhonghua yagao",
"desc" : "caoben zhiwu",
"price" : 40,
"producer" : "zhonghua producer",
"tags": [ "qingxin" ]
}
es会自动建立index和type,不需要提前创建,而且es默认会对document每个field都建立倒排索引,让其可以被搜索
(2)查询商品:检索文档
GET /index/type/id
GET /ecommerce/product/1
{
"_index": "ecommerce",
"_type": "product",
"_id": "1",
"_version": 1,
"found": true,
"_source": {
"name": "gaolujie yagao",
"desc": "gaoxiao meibai",
"price": 30,
"producer": "gaolujie producer",
"tags": [
"meibai",
"fangzhu"
]
}
}
(3)修改商品:替换文档
PUT /ecommerce/product/1
{
"name" : "jiaqiangban gaolujie yagao",
"desc" : "gaoxiao meibai",
"price" : 30,
"producer" : "gaolujie producer",
"tags": [ "meibai", "fangzhu" ]
}
{
"_index": "ecommerce",
"_type": "product",
"_id": "1",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"created": true
}
{
"_index": "ecommerce",
"_type": "product",
"_id": "1",
"_version": 2,
"result": "updated",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"created": false
}
PUT /ecommerce/product/1
{
"name" : "jiaqiangban gaolujie yagao"
}
替换方式有一个不好,即使必须带上所有的field,才能去进行信息的修改
(4)修改商品:更新文档
POST /ecommerce/product/1/_update
{
"doc": {
"name": "jiaqiangban gaolujie yagao"
}
}
{
"_index": "ecommerce",
"_type": "product",
"_id": "1",
"_version": 8,
"result": "updated",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
}
}
我的风格,其实有选择的情况下,不太喜欢念ppt,或者照着文档做,或者直接粘贴写好的代码,尽量是纯手敲代码
(5)删除商品:删除文档
DELETE /ecommerce/product/1
{
"found": true,
"_index": "ecommerce",
"_type": "product",
"_id": "1",
"_version": 9,
"result": "deleted",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
}
}
{
"_index": "ecommerce",
"_type": "product",
"_id": "1",
"found": false
}
where (select count(*) from student where class=a.class and a.score<score)<3
order by a.class,a.score desc;
git config --global http.sslVerify false
public class Test {
//不能正确调换值
public static void swap(Integer a,Integer b){
Integer t=a;
a=b;
b=t;
System.out.println("a="+a);
System.out.println("b="+b);
}
public static void main(String[] args) {
Integer a=1;
Integer b=2;
System.out.println("a="+a);
System.out.println("b="+b);
System.out.println("----------");
swap(a, b);
System.out.println("----------");
System.out.println("a="+a);
System.out.println("b="+b);
}
}
在内存中,真实的值放在heap中,变量a,b放在栈中,a,b保存的是值在heap中的地址,当调用swap方法时,形参也是保存在栈中,是新的变量,指向heap中真的值,并没有修改原先a,b的指向,所以无法交换值。
matches方法返回true,装配bean,返回false,不装配bean,在需要可能装配的bean的方法和类上加上注解@Conditional(XXXCondition.class)
@Component
public class AllBeanPostProcessor implements BeanPostProcessor{
//对象属性设置方法完成后,init方法执行前执行
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("BeforeInit="+beanName);
return bean;
}
//init方法执行后执行
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("AfterInit="+beanName);
return bean;
}
}
@Component
public class MyBeanFactoryPostProcessor2 implements BeanDefinitionRegistryPostProcessor{
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// TODO Auto-generated method stub
}
//可以动态把对象注入spring对象
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
for (int i = 0; i < 10; i++) {
BeanDefinitionBuilder b=BeanDefinitionBuilder.rootBeanDefinition(User.class);
b.addPropertyValue("name", "admin"+i);
registry.registerBeanDefinition("user"+i, b.getBeanDefinition());
}
}
}
关键字
package test;
public class TestThread extends Thread{
private volatile boolean stop=false;
@Override
public void run() {
int i=0;
while(!stop){
i++;
}
System.out.println("完成="+i);
}
public void setStop(){
stop=true;
}
public boolean getStop(){
return stop;
}
}
volatile关键字只能保证多个线程间的可见性,但是不具备同步性,可以算得上是轻量级的
synchronized,性能要比synchronized高,不会造成阻塞。一般volatile用于多个线程之间的可见的变量操作,并不能代替synchronized的同步功能。
例如:9点的时候,客户A发起select语句,大概需要执行10分钟,返回结果100,在9点5分的时候,客户B发起一条update语句,把100更新为200.当10分钟后,客户A得到的结果还是100或者返回异常snapshot too old。因为oracle数据库有数据一致性的保证,客户9点查询时,数据库会把数据复制到undo的副本,给客户返回的就是这个副本,如果同时多个客户端进行update操作,可能导致副本找不到,但是无论如何,不会返回修改过的数值。
在一个对象中的多个方法上都加上synchronized,代表同时执行这些方法时,是同步的,同步锁是属于对象的不是单个方法的。
package test;
public class Test6 {
public synchronized void get1(String s){
System.out.println(s);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void get2(String s){
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(s);
}
public static void main(String[] args) {
final Test6 t =new Test6();
new Thread(new Runnable() {
@Override
public void run() {
t.get1("a");
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
t.get2("b");
}
}).start();
}
}
多个线程访问同多个对象,同步方法加static,表示此方法属于类,所有此对象的此方法执行需要同步
package test;
public class Test5 {
public static synchronized void get(String s){
if("a".equals(s)){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(s);
}
public static void main(String[] args) {
final Test5 t =new Test5();
final Test5 t1 =new Test5();
new Thread(new Runnable() {
@Override
public void run() {
t.get("a");
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
t1.get("b");
}
}).start();
}
}
多个线程使用一把锁,多个线程访问同一个对象的方法或者属性。
package test;
public class Test4 {
public synchronized void get(String s){
if("c".equals(s)){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(s);
}
public static void main(String[] args) {
final Test4 t =new Test4();
new Thread(new Runnable() {
@Override
public void run() {
t.get("a");
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
t.get("b");
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
t.get("c");
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
t.get("d");
}
}).start();
}
}
1、安装cmake (可能需要安装 yum install gcc-c++)
2、安装yum install ncurses-devel -y
3.创建用户和组 groupadd mysql
useradd mysql -s /sbin/nologin -M -g mysql
4、tar xf mysql-5.5.32.tar.gz
5、进入MySQL目录,(可能需要 yum install bison)执行
cmake . -DCMAKE_INSTALL_PREFIX=/usr/local/mysql -DMYSQL_DATADIR=/usr/local/mysql/data -DMYSQL_UNIX_ADDR=/tmp/mysql.sock -DDEFAULT_CHARSET=utf8 -DDEFAULT_COLLATION=utf8_general_ci -DEXTRA_CHARSETS=all -DENABLED_LOCAL_INFILE=ON -DWITH_INNOBASE_STORAGE_ENGINE=1 -DWITH_BLACKHOLE_STORAGE_ENGINE=1 -DWITHOUT_EXAMPLE_STORAGE_ENGINE=1 -DWITHOUT_PARTITION_STORAGE_ENGINE=1 -DWITH_FAST_MUTEXES=1 -DWITH_ZLIB=bundled -DENABLED_LOCAL_INFILE=1 -DWITH_READLINE=1 -DWITH_EMBEDDED_SERVER=1 -DWITH_DEBUG=0 -DMYSQL_TCP_PORT=3306
6、make && make install
7、cp mysql-5.5.32/support-files/my-small.cnf /etc/my.cnf
8、添加环境变量 export PATH=/usr/local/mysql/bin:$PATH
9、授权 chown -R mysql.mysql /usr/local/mysql/data/
10、chmod -R 1777 /tmp/
11、在MySQL的安装目录下的scripts文件夹下,执行./mysql_install_db --basedir=/usr/local/mysql/ --datadir=/usr/local/mysql/data/ --user=mysql
12、负责MySQL启动命令 cp support-files/mysql.server /etc/init.d/mysqld
13、授权chmod +x /etc/init.d/mysqld
14、启动MySQL /etc/init.d/mysqld start
15、查看运行的进程 netstat -lntup|grep 3306
16、删除无用的用户和host,select user,host from mysql.user ;
删除test数据库
17、删除root用户,添加别的数据库管理员
delete from mysql.user;
grant all privileges on *.* to system@'localhost' identified by 'yjw' with grant option;
/usr/local/mysql//bin/mysqladmin -u root password 'new-password' --设置密码
/usr/local/mysql//bin/mysqladmin -u root -h bogon password 'root' --修改密码
linux下GTK+的一键安装和配置:(fedora16和centos下配置成功)
必要组件:
yum install gtk2 gtk2-devel gtk2-devel-docs
可选组件:
yum install gnome-devel gnome-devel-docs
A Java Runtime Environment (JRE) or Java Development Kit (JDK)
must be available in order to run Eclipse. No Java virtual machine
was found after searching the following locations:
/home/injavawetrust/program/eclipse/jre/bin/java
java in your current PATH
解决办法是在终端进入你的eclipse目录,然后输入:
mkdir jre
cd jre
ln -s 你的JDK目录/bin bin
方法一:
如果你是用命令行提交的,可以用以下命令设置临时环境变量GIT_SSL_NO_VERIFY。
Windows下:
set GIT_SSL_NO_VERIFY=true git push
Linux下:
env GIT_SSL_NO_VERIFY=true git push
设置好之后,然后用Git提交。
当然,你也可以把GIT_SSL_NO_VERIFY设置成非临时环境变量,这样就不用每次提交都要执行上面的命令了。
方法二:
你也可以在命令行执行以下命令,之后再提交。
git config --global http.sslVerify false
以上两个方法,亲测有效,建议第二个,直接去掉git的ssl验证
1、不在启动类同级的包目录中新建ribbon配置类
@Configuration
public class TestConfiguration {
@Autowired
IClientConfig config;
@Bean
public IRule ribbonRule(IClientConfig config) {
return new RandomRule();
}
}
在启动类中添加注解@RibbonClient
@SpringBootApplication
@EnableEurekaClient //针对Eureka服务注册使用
//@EnableDiscoveryClient //可以对其他服务注册软件使用
@RibbonClient(name="a-microservice-provider-user",configuration=TestConfiguration.class)
public class ConsumerMovieRibbonApplication {
@Bean
@LoadBalanced//客户端负载均衡,先把服务提供这所有的节点读取到ribbon注册表中,默认轮询请求服务
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(ConsumerMovieRibbonApplication.class, args);
}
}
3.在controller中添加方法
@GetMapping("/movie/{userid}")
public TUser test2(@PathVariable(name="userid") String userId) {
//服务的自动发现,不用配置死的IP和端口,只有在RestTemplate添加了@LoadBalanced接口,才能使用应用名称访问
return restTemplate.getForObject("http://a-microservice-provider-user/users/"+userId, TUser.class);
}
4、启动服务发现服务eureka和服务提供类,调用目标方法,可以成功 调用。
一、服务端的搭建
1、在pom文件中添加eureka服务依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
2、编写application.yml 配置
security:
basic:
enabled: true
user:
name: user
password: password123
server:
port: 8761
eureka:
client:
register-with-eureka: false #只把此服务当成eurekaservice,不要当成client
fetch-registry: false #只把此服务当成eurekaservice,不要当成client
service-url:
defaultZone: http://user:password123@localhost:8761/eureka
3、在启动类上添加注解
@SpringBootApplication
@EnableEurekaServer
就可以启动服务发现的服务端程序了。
二、客户端的搭建
1、在pom文件中添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
2、编写application.yml 配置
server:
port: 7901
session-timeout: 30
tomcat.max-threads: 0
tomcat.uri-encoding: UTF-8
spring:
application:
name: a-microservice-consumer-movie
logging:
level:
root: INFO
com.example.demo: debug
eureka:
client:
serviceUrl:
defaultZone: http://user:password123@localhost:8761/eureka
instance: #eureka管理页面客户端服务的地址显示实际IP
prefer-ip-address: true #默认是false
3、在启动类添加注解
@SpringBootApplication
@EnableEurekaClient //针对Eureka服务注册使用
//@EnableDiscoveryClient //可以对其他服务注册软件使用
这样客户端配置完毕,先启动服务端,再启动客户端,服务端就可以自动发现客户端服务了。
springboot的应用打包默认是打成jar包,并且如果是web应用的话,默认使用内置的tomcat充当servlet容器,但毕竟内置的tomcat有时候并不满足我们的需求,如有时候我们想集群或者其他一些特性优化配置,因此我们需要把springboot的jar应用打包成war包,并能够在外部tomcat中运行。
很多人会疑问,你直接打成war包并部署到tomcat的webapp下不就行了么?No,springboot的如果在类路径下有tomcat相关类文件,就会以内置tomcat启动的方式,经过你把war包扔到外置的tomcat的webapp文件下启动springBoot应用也无事于补。
要把springboot应用转至外部tomcat的操作主要有以下三点:
1、把pom.xml文件中打包结果由jar改成war,如下:
- <modelVersion>4.0.0</modelVersion>
- <groupId>spring-boot-panminlan-mybatis-test</groupId>
- <artifactId>mybatis-test</artifactId>
- <packaging>war</packaging>
- <version>0.0.1-SNAPSHOT</version>
2、添加maven的war打包插件如下:并且给war包起一个名字,tomcat部署后的访问路径会需要,如:http:localhost:8080/myweb/****
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-war-plugin</artifactId>
- <configuration>
- <warSourceExcludes>src/main/resources/**</warSourceExcludes>
- <warName>myweb</warName>
- </configuration>
- </plugin>
3、排除org.springframework.boot依赖中的tomcat内置容器,这是很重要的一步
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- <exclusions>
- <exclusion>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-tomcat</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
4、添加对servlet API的依赖
- <dependency>
- <groupId>javax.servlet</groupId>
- <artifactId>javax.servlet-api</artifactId>
- </dependency>
5、继承SpringBootServletInitializer
,并覆盖它的 configure
方法,如下图代码,为什么需要提供这样一个SpringBootServletInitializer子类并覆盖它的config方法呢,我们看下该类原代码的注释:
/**Note that a WebApplicationInitializer is only needed if you are building a war file and
* deploying it. If you prefer to run an embedded container then you won't need this at
* all.
如果我们构建的是wai包并部署到外部tomcat则需要使用它,如果使用内置servlet容器则不需要,外置tomcat环境的配置需要这个类的configure方法来指定初始化资源。
//@ServletComponentScan
public class JobManagementApplication extends SpringBootServletInitializer{
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(JobManagementApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(JobManagementApplication.class, args);
}
}
经过以上配置,我们把构建好的war包拷到tomcat的webapp下,启动tomcat就可以访问啦
在pom文件中加入
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
<scope>true</scope>
</dependency>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork>
</configuration>
</plugin>
第一种配置方法:
在实体类中加入格式化属性的注解
public class User implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private Integer id;
private String username;
private Date birthday;
private Integer age;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@JSONField(format="yyyy-MM-dd hh:MM:ss")
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
2.在启动类中继承类
@SpringBootApplication
public class Demo1Application2 extends WebMvcConfigurerAdapter{
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
super.configureMessageConverters(converters);
FastJsonHttpMessageConverter fastConverter=new FastJsonHttpMessageConverter();
FastJsonConfig fastJsonConfig = new FastJsonConfig();
fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);
fastConverter.setFastJsonConfig(fastJsonConfig);
converters.add(fastConverter);
}
public static void main(String[] args) {
SpringApplication app=new SpringApplication(Demo1Application2.class);
ConfigurableApplicationContext context = app.run( args);
//context.close();
}
}
3.访问页面,请求方法,得到结果
{ "age":11, "birthday":"2018-03-15 10:03:55", "id":1, "username":"dddd" }第二种配置方法:在启动类加入一个bean@SpringBootApplication
public class Demo1Application3 {
@Bean
public HttpMessageConverters fastJsonHttpMessageConverters() {
FastJsonHttpMessageConverter fastConverter=new FastJsonHttpMessageConverter();
FastJsonConfig fastJsonConfig = new FastJsonConfig();
fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);
fastConverter.setFastJsonConfig(fastJsonConfig);
HttpMessageConverter<?> converters=fastConverter;
return new HttpMessageConverters(converters);
}
public static void main(String[] args) {
SpringApplication app=new SpringApplication(Demo1Application3.class);
ConfigurableApplicationContext context = app.run( args);
//context.close();
}
}
1、aop的简单实现
public class User implements InitializingBean,DisposableBean{
public String toString() {
System.out.println("userdddd");
return "444";
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println(" user afterPropertiesSet");
}
@Override
public void destroy() throws Exception {
System.out.println("user destroy");
}
}
public class LogUser extends User{
public String toString() {
System.out.println("log start");
super.toString();
System.out.println("log end");
return "";
}
}
public interface MyApplicationContextAware {
void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}
@Component
public class Dog4 implements MyApplicationContextAware{
ApplicationContext applicationContext;
public ApplicationContext getApplicationContext() {
return applicationContext;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext=applicationContext;
}
}
@Component
public class MyBeanPostProcessor implements BeanPostProcessor{
@Autowired
ApplicationContext applicationContext;
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessAfterInitialization=="+beanName);
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessBeforeInitialization=="+beanName);
if(bean instanceof User) {
return new LogUser();
}
if(bean instanceof MyApplicationContextAware) {
MyApplicationContextAware my=(MyApplicationContextAware) bean;
my.setApplicationContext(applicationContext);
}
return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
}
}
public class App {
public static void main(String[] args) {
AnnotationConfigApplicationContext aa=new AnnotationConfigApplicationContext("com.yjw");
Dog4 dog = aa.getBean(Dog4.class);
System.out.println(dog.getApplicationContext());
User user = aa.getBean(User.class);
System.out.println(user.toString());
aa.close();
}
}
@Component
public class MyBeanPostProcessor implements BeanPostProcessor{
//在每个bean初始化后,初始化方法执行后,都执行
的方法
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessAfterInitialization=="+beanName);
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}
//在每个bean初始化后,在初始化方法执行前,都执行的方法
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessBeforeInitialization=="+beanName);
return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
}
}
三种初始化方式
public class Cat {
@PostConstruct//初始化
public void afterPropertiesSet() throws Exception {
System.out.println(" cat init");
}
@PreDestroy//销毁
public void destroy() throws Exception {
System.out.println("cat destroy");
}
}
public class User implements InitializingBean,DisposableBean{
public String toString() {
return "444";
}
@Override//初始化
public void afterPropertiesSet() throws Exception {
System.out.println(" user afterPropertiesSet");
}
@Override//销毁
public void destroy() throws Exception {
System.out.println("user destroy");
}
}
public class Room {
//初始化
public void afterPropertiesSet() throws Exception {
System.out.println(" room afterPropertiesSet");
}
//销毁
public void destroy() throws Exception {
System.out.println("room destroy");
}
}
@Configuration
public class Cfg1 {
@Bean
public Cat getCat() {
return new Cat();
}
@Bean
public User getUser() {
return new User();
}
@Bean(initMethod="afterPropertiesSet",destroyMethod="destroy")
public Room getRoom() {
return new Room();
}
}
@Configuration
public class RedisClusterConfig {
@Value("${spring.redis.cluster.nodes}")
private String clusterNodes;
@Bean
public JedisCluster getJedisCluster() {
// 截取集群节点
String[] cluster = clusterNodes.split(",");
// 创建set集合
Set<HostAndPort> nodes = new HashSet<HostAndPort>();
// 循环数组把集群节点添加到set集合中
for (String node : cluster) {
String[] host = node.split(":");
//添加集群节点
nodes.add(new HostAndPort(host[0], Integer.parseInt(host[1])));
}
JedisCluster jc = new JedisCluster(nodes);
return jc;
}
}
在application.properties文件中,配置spring.redis.cluster.nodes=
在使用的时候直接得到JedisCluster对象使用
一、Redis提供了哪些持久化机制:
1). RDB持久化:
该机制是指在指定的时间间隔内将内存中的数据集快照写入磁盘。
2). AOF持久化:
该机制将以日志的形式记录服务器所处理的每一个写操作,在Redis服务器启动之初会读取该文件来重新构建数据库,以保证启动后数据库中的数据是完整的。
3). 无持久化:
我们可以通过配置的方式禁用Redis服务器的持久化功能,这样我们就可以将Redis视为一个功能加强版的memcached了。
4). 同时应用AOF和RDB。
二、RDB机制的优势和劣势:
RDB存在哪些优势呢?
1). 一旦采用该方式,那么你的整个Redis数据库将只包含一个文件,这对于文件备份而言是非常完美的。比如,你可能打算每个小时归档一次最近24小时的数据,同时还要每天归档一次最近30天的数据。通过这样的备份策略,一旦系统出现灾难性故障,我们可以非常容易的进行恢复。
2). 对于灾难恢复而言,RDB是非常不错的选择。因为我们可以非常轻松的将一个单独的文件压缩后再转移到其它存储介质上。
3). 性能最大化。对于Redis的服务进程而言,在开始持久化时,它唯一需要做的只是fork出子进程,之后再由子进程完成这些持久化的工作,这样就可以极大的避免服务进程执行IO操作了。
4). 相比于AOF机制,如果数据集很大,RDB的启动效率会更高。
RDB又存在哪些劣势呢?
1). 如果你想保证数据的高可用性,即最大限度的避免数据丢失,那么RDB将不是一个很好的选择。因为系统一旦在定时持久化之前出现宕机现象,此前没有来得及写入磁盘的数据都将丢失。
2). 由于RDB是通过fork子进程来协助完成数据持久化工作的,因此,如果当数据集较大时,可能会导致整个服务器停止服务几百毫秒,甚至是1秒钟。
三、AOF机制的优势和劣势:
AOF的优势有哪些呢?
1). 该机制可以带来更高的数据安全性,即数据持久性。Redis中提供了3中同步策略,即每秒同步、每修改同步和不同步。事实上,每秒同步也是异步完成的,其效率也是非常高的,所差的是一旦系统出现宕机现象,那么这一秒钟之内修改的数据将会丢失。而每修改同步,我们可以将其视为同步持久化,即每次发生的数据变化都会被立即记录到磁盘中。可以预见,这种方式在效率上是最低的。至于无同步,无需多言,我想大家都能正确的理解它。
2). 由于该机制对日志文件的写入操作采用的是append模式,因此在写入过程中即使出现宕机现象,也不会破坏日志文件中已经存在的内容。然而如果我们本次操作只是写入了一半数据就出现了系统崩溃问题,不用担心,在Redis下一次启动之前,我们可以通过redis-check-aof工具来帮助我们解决数据一致性的问题。
3). 如果日志过大,Redis可以自动启用rewrite机制。即Redis以append模式不断的将修改数据写入到老的磁盘文件中,同时Redis还会创建一个新的文件用于记录此期间有哪些修改命令被执行。因此在进行rewrite切换时可以更好的保证数据安全性。
4). AOF包含一个格式清晰、易于理解的日志文件用于记录所有的修改操作。事实上,我们也可以通过该文件完成数据的重建。
AOF的劣势有哪些呢?
1). 对于相同数量的数据集而言,AOF文件通常要大于RDB文件。
2). 根据同步策略的不同,AOF在运行效率上往往会慢于RDB。总之,每秒同步策略的效率是比较高的,同步禁用策略的效率和RDB一样高效。
四、其它:
1. Snapshotting:
缺省情况下,Redis会将数据集的快照dump到dump.rdb文件中。此外,我们也可以通过配置文件来修改Redis服务器dump快照的频率,在打开6379.conf文件之后,我们搜索save,可以看到下面的配置信息:
save 900 1 #在900秒(15分钟)之后,如果至少有1个key发生变化,则dump内存快照。
save 300 10 #在300秒(5分钟)之后,如果至少有10个key发生变化,则dump内存快照。
save 60 10000 #在60秒(1分钟)之后,如果至少有10000个key发生变化,则dump内存快照。
2. Dump快照的机制:
1). Redis先fork子进程。
2). 子进程将快照数据写入到临时RDB文件中。
3). 当子进程完成数据写入操作后,再用临时文件替换老的文件。
3. AOF文件:
上面已经多次讲过,RDB的快照定时dump机制无法保证很好的数据持久性。如果我们的应用确实非常关注此点,我们可以考虑使用Redis中的AOF机制。对于Redis服务器而言,其缺省的机制是RDB,如果需要使用AOF,则需要修改配置文件中的以下条目:
将appendonly no改为appendonly yes
从现在起,Redis在每一次接收到数据修改的命令之后,都会将其追加到AOF文件中。在Redis下一次重新启动时,需要加载AOF文件中的信息来构建最新的数据到内存中。
4. AOF的配置:
在Redis的配置文件中存在三种同步方式,它们分别是:
appendfsync always #每次有数据修改发生时都会写入AOF文件。
appendfsync everysec #每秒钟同步一次,该策略为AOF的缺省策略。
appendfsync no #从不同步。高效但是数据不会被持久化。
5. 如何修复坏损的AOF文件:
1). 将现有已经坏损的AOF文件额外拷贝出来一份。
2). 执行"redis-check-aof --fix <filename>"命令来修复坏损的AOF文件。
3). 用修复后的AOF文件重新启动Redis服务器。
6. Redis的数据备份:
在Redis中我们可以通过copy的方式在线备份正在运行的Redis数据文件。这是因为RDB文件一旦被生成之后就不会再被修改。Redis每次都是将最新的数据dump到一个临时文件中,之后在利用rename函数原子性的将临时文件改名为原有的数据文件名。因此我们可以说,在任意时刻copy数据文件都是安全的和一致的。鉴于此,我们就可以通过创建cron job的方式定时备份Redis的数据文件,并将备份文件copy到安全的磁盘介质中。
安装
1/到官网下载最新stable版
2/解压源码并进入目录
3/ make
4/ 可选 make test (可能出现need tcl>8.4,yum install tcl)
5/安装到指定目录,如 /usr/local/redis
make PREFIX=/usr/local/redis install
运行
./bin/redis-server redis-2.8.19/redis.conf
(默认前端运行模式。后台进程模式: 修改conf daemonize yes)
连接
[root@bogon redis]# ./bin/redis-cli
127.0.0.1:6379> set a bb
OK
127.0.0.1:6379> get a
"bb"
127.0.0.1:6379> get aa
(nil)
127.0.0.1:6379>
后来发现了logratate这个工具,Ubuntu
下的mysql,nginx好像也是用的这个工具还定期整理log的。配置文件为/etc/logrotate.conf,和很多其它ubuntu下的工
具一下,也可以把配置文件写在/etc/logrotate.d/下面。如对我们的tomcat的log文件进行整理,sudo vi
/etc/logrotate.d/tomcat,
/opt/tomcat/logs/catalina.out {
rotate 14
daily
copytruncate
compress
notifempty
missingok
}
其中:
rotate 7 表示保留7天的备份文件
daily 表示每天整理一次
copytruncate 表示先复制log文件的内容,然后再清空
compress 表示压缩备分文件
missingok 表示如果找不到log文件也没OK
notifempty 表示如果log文件是空的,就不进行rotate
可以通过/usr/sbin/logrotate -f /etc/logrotate.conf来执行。Ubuntu
有/etc/cron.daily/logrotate文件,内容为:
#!/bin/sh
test -x /usr/sbin/logrotate || exit 0
/usr/sbin/logrotate /etc/logrotate.conf
表示每天会定时执行一次这个命令
通过ntp同步服务器的时间
根据 Ubuntu 的文档 有两种方式可以用来使服务器的时间和ntp server同步。一种是通过ntpdate命令,如
ntpdate ntp.Ubuntu .com
然后在/etc/cron.daily/下新建一个文件来每天执行一次这个命令
另一种是通过ntpd来更新。sudo apt-get install
ntp。配置文件/etc/ntp.conf,可以通过修改配置文件为改变ntp server,
我们用的是210.72.145.44这个server
对于Linux 的系统安全来说,日志文件是极其重要的工具。系统管理员可以使用logrotate
程序用来管理系统中的最新的事件,对于Linux 的系统安全来说,日志文件是极其重要的工具。系统管理员可以使用logrotate
程序用来管理系统中的最新的事件。logrotate 还可以用来备份日志文件,本篇将通过以下几部分来介绍
日志文件的管理:
1、logrotate 配置
2、缺省配置 logrotate
3、使用include 选项读取其他配置文件
4、使用include 选项覆盖缺省配置
5、为指定的文件配置转储参数
一、logrotate 配置
logrotate
程序是一个日志文件管理工具。用来把旧的日志文件删除,并创建新的日志文件,我们把它叫做“转储”。我们可以根据日志文件的大小,也可以根据其天数来转储,这个过程一般通过
cron 程序来执行。
logrotate 程序还可以用于压缩日志文件,以及发送日志到指定的E-mail 。
logrotate 的配置文件是 /etc/logrotate.conf。主要参数如下表:
参数 功能
compress 通过gzip 压缩转储以后的日志
nocompress 不需要压缩时,用这个参数
copytruncate 用于还在打开中的日志文件,把当前日志备份并截断
nocopytruncate 备份日志文件但是不截断
create mode owner group 转储文件,使用指定的文件模式创建新的日志文件
nocreate 不建立新的日志文件
delaycompress 和 compress 一起使用时,转储的日志文件到下一次转储时才压缩
nodelaycompress 覆盖 delaycompress 选项,转储同时压缩。
errors address 专储时的错误信息发送到指定的Email 地址
ifempty 即使是空文件也转储,这个是 logrotate 的缺省选项。
notifempty 如果是空文件的话,不转储
mail address 把转储的日志文件发送到指定的E-mail 地址
nomail 转储时不发送日志文件
olddir directory 转储后的日志文件放入指定的目录,必须和当前日志文件在同一个文件系统
noolddir 转储后的日志文件和当前日志文件放在同一个目录下
prerotate/endscript 在转储以前需要执行的命令可以放入这个对,这两个关键字必须单独成行
postrotate/endscript 在转储以后需要执行的命令可以放入这个对,这两个关键字必须单独成行
daily 指定转储周期为每天
weekly 指定转储周期为每周
monthly 指定转储周期为每月
rotate count 指定日志文件删除之前转储的次数,0 指没有备份,5 指保留5 个备份
tabootext [+] list 让logrotate 不转储指定扩展名的文件,缺省的扩展名是:.rpm-orig,
.rpmsave, v, 和 ~
size size 当日志文件到达指定的大小时才转储,Size 可以指定 bytes (缺省)以及KB
(sizek)或者MB (sizem).cat /dev/null >catalina.out
后来发现了logratate这个工具,Ubuntu
下的mysql,nginx好像也是用的这个工具还定期整理log的。配置文件为/etc/logrotate.conf,和很多其它ubuntu下的工
具一下,也可以把配置文件写在/etc/logrotate.d/下面。如对我们的tomcat的log文件进行整理,sudo vi
/etc/logrotate.d/tomcat,
/opt/tomcat/logs/catalina.out {
rotate 14
daily
copytruncate
compress
notifempty
missingok
}
其中:
rotate 7 表示保留7天的备份文件
daily 表示每天整理一次
copytruncate 表示先复制log文件的内容,然后再清空
compress 表示压缩备分文件
missingok 表示如果找不到log文件也没OK
notifempty 表示如果log文件是空的,就不进行rotate
可以通过/usr/sbin/logrotate -f /etc/logrotate.conf来执行。Ubuntu
有/etc/cron.daily/logrotate文件,内容为:
#!/bin/sh
test -x /usr/sbin/logrotate || exit 0
/usr/sbin/logrotate /etc/logrotate.conf
表示每天会定时执行一次这个命令
通过ntp同步服务器的时间
根据 Ubuntu 的文档 有两种方式可以用来使服务器的时间和ntp server同步。一种是通过ntpdate命令,如
ntpdate ntp.Ubuntu .com
然后在/etc/cron.daily/下新建一个文件来每天执行一次这个命令
另一种是通过ntpd来更新。sudo apt-get install
ntp。配置文件/etc/ntp.conf,可以通过修改配置文件为改变ntp server,
我们用的是210.72.145.44这个server
对于Linux 的系统安全来说,日志文件是极其重要的工具。系统管理员可以使用logrotate
程序用来管理系统中的最新的事件,对于Linux 的系统安全来说,日志文件是极其重要的工具。系统管理员可以使用logrotate
程序用来管理系统中的最新的事件。logrotate 还可以用来备份日志文件,本篇将通过以下几部分来介绍
日志文件的管理:
1、logrotate 配置
2、缺省配置 logrotate
3、使用include 选项读取其他配置文件
4、使用include 选项覆盖缺省配置
5、为指定的文件配置转储参数
一、logrotate 配置
logrotate
程序是一个日志文件管理工具。用来把旧的日志文件删除,并创建新的日志文件,我们把它叫做“转储”。我们可以根据日志文件的大小,也可以根据其天数来转储,这个过程一般通过
cron 程序来执行。
logrotate 程序还可以用于压缩日志文件,以及发送日志到指定的E-mail 。
logrotate 的配置文件是 /etc/logrotate.conf。主要参数如下表:
参数 功能
compress 通过gzip 压缩转储以后的日志
nocompress 不需要压缩时,用这个参数
copytruncate 用于还在打开中的日志文件,把当前日志备份并截断
nocopytruncate 备份日志文件但是不截断
create mode owner group 转储文件,使用指定的文件模式创建新的日志文件
nocreate 不建立新的日志文件
delaycompress 和 compress 一起使用时,转储的日志文件到下一次转储时才压缩
nodelaycompress 覆盖 delaycompress 选项,转储同时压缩。
errors address 专储时的错误信息发送到指定的Email 地址
ifempty 即使是空文件也转储,这个是 logrotate 的缺省选项。
notifempty 如果是空文件的话,不转储
mail address 把转储的日志文件发送到指定的E-mail 地址
nomail 转储时不发送日志文件
olddir directory 转储后的日志文件放入指定的目录,必须和当前日志文件在同一个文件系统
noolddir 转储后的日志文件和当前日志文件放在同一个目录下
prerotate/endscript 在转储以前需要执行的命令可以放入这个对,这两个关键字必须单独成行
postrotate/endscript 在转储以后需要执行的命令可以放入这个对,这两个关键字必须单独成行
daily 指定转储周期为每天
weekly 指定转储周期为每周
monthly 指定转储周期为每月
rotate count 指定日志文件删除之前转储的次数,0 指没有备份,5 指保留5 个备份
tabootext [+] list 让logrotate 不转储指定扩展名的文件,缺省的扩展名是:.rpm-orig,
.rpmsave, v, 和 ~
size size 当日志文件到达指定的大小时才转储,Size 可以指定 bytes (缺省)以及KB
(sizek)或者MB (sizem).
原文来自http://note.youdao.com/share/web/file.html?id=236896997b6ffbaa8e0d92eacd13abbf&type=note
我怕链接会失效,故转载此篇文章
由于linux目前很热门,越来越多的人在学习linux,但是买一台服务放家里来学习,实在是很浪费。那么如何解决这个问题?虚拟机软件是很好的选择,常用的虚拟机软件有vmware workstations和virtual box等。在使用虚拟机软件的时候,很多初学者都会遇到很多问题,而vmware的网络连接问题是大家遇到最多问题之一。在学习交流群里面,几乎每天都会有同学问到这些问题,写这篇详解也是因为群里童鞋网络出故障,然后在帮他解决的过程中,对自己的理解也做一个总结。接下来,我们就一起来探讨一下关于vmware workstations网络连接的三种模式。
vmware为我们提供了三种网络工作模式,它们分别是:Bridged(桥接模式)、NAT(网络地址转换模式)、Host-Only(仅主机模式)。
打开vmware虚拟机,我们可以在选项栏的“编辑”下的“虚拟网络编辑器”中看到VMnet0(桥接模式)、VMnet1(仅主机模式)、VMnet8(NAT模式),那么这些都是有什么作用呢?其实,我们现在看到的VMnet0表示的是用于桥接模式下的虚拟交换机;VMnet1表示的是用于仅主机模式下的虚拟交换机;VMnet8表示的是用于NAT模式下的虚拟交换机。
同时,在主机上对应的有VMware Network Adapter VMnet1和VMware Network Adapter VMnet8两块虚拟网卡,它们分别作用于仅主机模式与NAT模式下。在“网络连接”中我们可以看到这两块虚拟网卡,如果将这两块卸载了,可以在vmware的“编辑”下的“虚拟网络编辑器”中点击“还原默认设置”,可重新将虚拟网卡还原。
小伙伴看到这里,肯定有疑问,为什么在真机上没有VMware Network Adapter VMnet0虚拟网卡呢?那么接下来,我们就一起来看一下这是为什么。
一、Bridged(桥接模式)
什么是桥接模式?桥接模式就是将主机网卡与虚拟机虚拟的网卡利用虚拟网桥进行通信。在桥接的作用下,类似于把物理主机虚拟为一个交换机,所有桥接设置的虚拟机连接到这个交换机的一个接口上,物理主机也同样插在这个交换机当中,所以所有桥接下的网卡与网卡都是交换模式的,相互可以访问而不干扰。在桥接模式下,虚拟机ip地址需要与主机在同一个网段,如果需要联网,则网关与DNS需要与主机网卡一致。其网络结构如下图所示:
接下来,我们就来实际操作,如何设置桥接模式。
首先,安装完系统之后,在开启系统之前,点击“编辑虚拟机设置”来设置网卡模式。
点击“网络适配器”,选择“桥接模式”,然后“确定”
在进入系统之前,我们先确认一下主机的ip地址、网关、DNS等信息。
然后,进入系统编辑网卡配置文件,命令为vi /etc/sysconfig/network-scripts/ifcfg-eth0
添加内容如下:
编辑完成,保存退出,然后重启虚拟机网卡,使用ping命令ping外网ip,测试能否联网。
能ping通外网ip,证明桥接模式设置成功。
那主机与虚拟机之间的通信是否正常呢?我们就用远程工具来测试一下。
主机与虚拟机通信正常。
这就是桥接模式的设置步骤,相信大家应该学会了如何去设置桥接模式了。桥接模式配置简单,但如果你的网络环境是ip资源很缺少或对ip管理比较严格的话,那桥接模式就不太适用了。如果真是这种情况的话,我们该如何解决呢?接下来,我们就来认识vmware的另一种网络模式:NAT模式。
二、NAT(地址转换模式)
刚刚我们说到,如果你的网络ip资源紧缺,但是你又希望你的虚拟机能够联网,这时候NAT模式是最好的选择。NAT模式借助虚拟NAT设备和虚拟DHCP服务器,使得虚拟机可以联网。其网络结构如下图所示:
在NAT模式中,主机网卡直接与虚拟NAT设备相连,然后虚拟NAT设备与虚拟DHCP服务器一起连接在虚拟交换机VMnet8上,这样就实现了虚拟机联网。那么我们会觉得很奇怪,为什么需要虚拟网卡VMware Network Adapter VMnet8呢?原来我们的VMware Network Adapter VMnet8虚拟网卡主要是为了实现主机与虚拟机之间的通信。在之后的设置步骤中,我们可以加以验证。
首先,设置虚拟机中NAT模式的选项,打开vmware,点击“编辑”下的“虚拟网络编辑器”,设置NAT参数及DHCP参数。
将虚拟机的网络连接模式修改成NAT模式,点击“编辑虚拟机设置”。
点击“网络适配器”,选择“NAT模式”
然后开机启动系统,编辑网卡配置文件,命令为vi /etc/sysconfig/network-scripts/ifcfg-eth0
具体配置如下:
编辑完成,保存退出,然后重启虚拟机网卡,动态获取ip地址,使用ping命令ping外网ip,测试能否联网。
之前,我们说过VMware Network Adapter VMnet8虚拟网卡的作用,那我们现在就来测试一下。
如此看来,虚拟机能联通外网,确实不是通过VMware Network Adapter VMnet8虚拟网卡,那么为什么要有这块虚拟网卡呢?
之前我们就说VMware Network Adapter VMnet8的作用是主机与虚拟机之间的通信,接下来,我们就用远程连接工具来测试一下。
然后,将VMware Network Adapter VMnet8启用之后,发现远程工具可以连接上虚拟机了。
那么,这就是NAT模式,利用虚拟的NAT设备以及虚拟DHCP服务器来使虚拟机连接外网,而VMware Network Adapter VMnet8虚拟网卡是用来与虚拟机通信的。
三、Host-Only(仅主机模式)
Host-Only模式其实就是NAT模式去除了虚拟NAT设备,然后使用VMware Network Adapter VMnet1虚拟网卡连接VMnet1虚拟交换机来与虚拟机通信的,Host-Only模式将虚拟机与外网隔开,使得虚拟机成为一个独立的系统,只与主机相互通讯。其网络结构如下图所示:
通过上图,我们可以发现,如果要使得虚拟机能联网,我们可以将主机网卡共享给VMware Network Adapter VMnet1网卡,从而达到虚拟机联网的目的。接下来,我们就来测试一下。
首先设置“虚拟网络编辑器”,可以设置DHCP的起始范围。
设置虚拟机为Host-Only模式。
开机启动系统,然后设置网卡文件。
保存退出,然后重启网卡,利用远程工具测试能否与主机通信。
主机与虚拟机之间可以通信,现在设置虚拟机联通外网。
我们可以看到上图有一个提示,强制将VMware Network Adapter VMnet1的ip设置成192.168.137.1,那么接下来,我们就要将虚拟机的DHCP的子网和起始地址进行修改,点击“虚拟网络编辑器”
重新配置网卡,将VMware Network Adapter VMnet1虚拟网卡作为虚拟机的路由。
重启网卡,然后通过 远程工具测试能否联通外网以及与主机通信。
测试结果证明可以使得虚拟机连接外网。
以上就是关于vmware三种网络模式的工作原理及配置详解。
Map<String,String> map=new HashMap<String,String>();
map.put("1", "222");
List<Map<String,String>> list = new ArrayList<Map<String,String>>();
list.add(map);
map=null;//没有效果,list中还是有数据
map.clear();//map没数据了
Map<String, String> map2 = list.get(0);
System.out.println(map2.size());
System.out.println(map2.get("1"));
背景
通过名字就知道,X-Forwarded-For 是一个 HTTP 扩展头部。HTTP/1.1(RFC 2616)协议并没有对它的定义,它最开始是由 Squid 这个缓存代理软件引入,用来表示 HTTP 请求端真实 IP。如今它已经成为事实上的标准,被各大 HTTP 代理、负载均衡等转发服务广泛使用,并被写入 RFC 7239(Forwarded HTTP Extension)标准之中。
X-Forwarded-For 请求头格式非常简单,就这样:
X-Forwarded-For: client, proxy1, proxy2
可以看到,XFF 的内容由「英文逗号 + 空格」隔开的多个部分组成,最开始的是离服务端最远的设备 IP,然后是每一级代理设备的 IP。
如果一个 HTTP 请求到达服务器之前,经过了三个代理 Proxy1、Proxy2、Proxy3,IP 分别为 IP1、IP2、IP3,用户真实 IP 为 IP0,那么按照 XFF 标准,服务端最终会收到以下信息:
X-Forwarded-For: IP0, IP1, IP2
Proxy3 直连服务器,它会给 XFF 追加 IP2,表示它是在帮 Proxy2 转发请求。列表中并没有 IP3,IP3 可以在服务端通过 Remote Address 字段获得。我们知道 HTTP 连接基于 TCP 连接,HTTP 协议中没有 IP 的概念,Remote Address 来自 TCP 连接,表示与服务端建立 TCP 连接的设备 IP,在这个例子里就是 IP3。
Remote Address 无法伪造,因为建立 TCP 连接需要三次握手,如果伪造了源 IP,无法建立 TCP 连接,更不会有后面的 HTTP 请求。不同语言获取 Remote Address 的方式不一样,例如 php 是 $_SERVER["REMOTE_ADDR"]
,Node.js 是 req.connection.remoteAddress
,但原理都一样。
问题
有了上面的背景知识,开始说问题。我用 Node.js 写了一个最简单的 Web Server 用于测试。HTTP 协议跟语言无关,这里用 Node.js 只是为了方便演示,换成任何其他语言都可以得到相同结论。另外本文用 Nginx 也是一样的道理,如果有兴趣,换成 Apache 或其他 Web Server 也一样。
下面这段代码会监听 9009
端口,并在收到 HTTP 请求后,输出一些信息:
JSvar http = require('http'); http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res.write('remoteAddress: ' + req.connection.remoteAddress + '\n'); res.write('x-forwarded-for: ' + req.headers['x-forwarded-for'] + '\n'); res.write('x-real-ip: ' + req.headers['x-real-ip'] + '\n'); res.end(); }).listen(9009, '0.0.0.0');
这段代码除了前面介绍过的 Remote Address 和 X-Forwarded-For
,还有一个 X-Real-IP
,这又是一个自定义头部字段。X-Real-IP
通常被 HTTP 代理用来表示与它产生 TCP 连接的设备 IP,这个设备可能是其他代理,也可能是真正的请求端。需要注意的是,X-Real-IP
目前并不属于任何标准,代理和 Web 应用之间可以约定用任何自定义头来传递这个信息。
现在可以用域名 + 端口号直接访问这个 Node.js 服务,再配一个 Nginx 反向代理:
NGINXlocation / { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_set_header X-NginX-Proxy true; proxy_pass http://127.0.0.1:9009/; proxy_redirect off; }
我的 Nginx 监听 80
端口,所以不带端口就可以访问 Nginx 转发过的服务。
测试直接访问 Node 服务:
BASHcurl http://t1.imququ.com:9009/ remoteAddress: 114.248.238.236 x-forwarded-for: undefined x-real-ip: undefined
由于我的电脑直接连接了 Node.js 服务,Remote Address 就是我的 IP。同时我并未指定额外的自定义头,所以后两个字段都是 undefined。
再来访问 Nginx 转发过的服务:
BASHcurl http://t1.imququ.com/ remoteAddress: 127.0.0.1 x-forwarded-for: 114.248.238.236 x-real-ip: 114.248.238.236
这一次,我的电脑是通过 Nginx 访问 Node.js 服务,得到的 Remote Address 实际上是 Nginx 的本地 IP。而前面 Nginx 配置中的这两行起作用了,为请求额外增加了两个自定义头:
proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
实际上,在生产环境中部署 Web 应用,一般都采用上面第二种方式,有很多好处。但这就引入一个隐患:很多 Web 应用为了获取用户真正的 IP,从 HTTP 请求头中获取 IP。
HTTP 请求头可以随意构造,我们通过 curl 的 -H
参数构造 X-Forwarded-For
和 X-Real-IP
,再来测试一把。
直接访问 Node.js 服务:
BASHcurl http://t1.imququ.com:9009/ -H 'X-Forwarded-For: 1.1.1.1' -H 'X-Real-IP: 2.2.2.2' remoteAddress: 114.248.238.236 x-forwarded-for: 1.1.1.1 x-real-ip: 2.2.2.2
对于 Web 应用来说,X-Forwarded-For
和 X-Real-IP
就是两个普通的请求头,自然就不做任何处理原样输出了。这说明,对于直连部署方式,除了从 TCP 连接中得到的 Remote Address 之外,请求头中携带的 IP 信息都不能信。
访问 Nginx 转发过的服务:
BASHcurl http://t1.imququ.com/ -H 'X-Forwarded-For: 1.1.1.1' -H 'X-Real-IP: 2.2.2.2' remoteAddress: 127.0.0.1 x-forwarded-for: 1.1.1.1, 114.248.238.236 x-real-ip: 114.248.238.236
这一次,Nginx 会在 X-Forwarded-For
后追加我的 IP;并用我的 IP 覆盖 X-Real-IP
请求头。这说明,有了 Nginx 的加工,X-Forwarded-For
最后一节以及 X-Real-IP
整个内容无法构造,可以用于获取用户 IP。
用户 IP 往往会被使用与跟 Web 安全有关的场景上,例如检查用户登录地区,基于 IP 做访问频率控制等等。这种场景下,确保 IP 无法构造更重要。经过前面的测试和分析,对于直接面向用户部署的 Web 应用,必须使用从 TCP 连接中得到的 Remote Address;对于部署了 Nginx 这样反向代理的 Web 应用,在正确配置了 Set Header 行为后,可以使用 Nginx 传过来的 X-Real-IP
或 X-Forwarded-For
最后一节(实际上它们一定等价)。
那么,Web 应用自身如何判断请求是直接过来,还是由可控的代理转发来的呢?在代理转发时增加额外的请求头是一个办法,但是不怎么保险,因为请求头太容易构造了。如果一定要这么用,这个自定义头要够长够罕见,还要保管好不能泄露出去。
判断 Remote Address 是不是本地 IP 也是一种办法,不过也不完善,因为在 Nginx 所处服务器上访问,无论直连还是走 Nginx 代理,Remote Address 都是 127.0.0.1。这个问题还好通常可以忽略,更麻烦的是,反向代理服务器和实际的 Web 应用不一定部署在同一台服务器上。所以更合理的做法是收集所有代理服务器 IP 列表,Web 应用拿到 Remote Address 后逐一比对来判断是以何种方式访问。
通常,为了简化逻辑,生产环境会封掉通过带端口直接访问 Web 应用的形式,只允许通过 Nginx 来访问。那是不是这样就没问题了呢?也不见得。
首先,如果用户真的是通过代理访问 Nginx,X-Forwarded-For
最后一节以及 X-Real-IP
得到的是代理的 IP,安全相关的场景只能用这个,但有些场景如根据 IP 显示所在地天气,就需要尽可能获得用户真实 IP,这时候 X-Forwarded-For
中第一个 IP 就可以排上用场了。这时候需要注意一个问题,还是拿之前的例子做测试:
BASHcurl http://t1.imququ.com/ -H 'X-Forwarded-For: unknown, <>"1.1.1.1' remoteAddress: 127.0.0.1 x-forwarded-for: unknown, <>"1.1.1.1, 114.248.238.236 x-real-ip: 114.248.238.236
X-Forwarded-For
最后一节是 Nginx 追加上去的,但之前部分都来自于 Nginx 收到的请求头,这部分用户输入内容完全不可信。使用时需要格外小心,符合 IP 格式才能使用,不然容易引发 SQL 注入或 XSS 等安全漏洞。
结论
- 直接对外提供服务的 Web 应用,在进行与安全有关的操作时,只能通过 Remote Address 获取 IP,不能相信任何请求头;
- 使用 Nginx 等 Web Server 进行反向代理的 Web 应用,在配置正确的前提下,要用
X-Forwarded-For
最后一节 或 X-Real-IP
来获取 IP(因为 Remote Address 得到的是 Nginx 所在服务器的内网 IP);同时还应该禁止 Web 应用直接对外提供服务; - 在与安全无关的场景,例如通过 IP 显示所在地天气,可以从
X-Forwarded-For
靠前的位置获取 IP,但是需要校验 IP 格式合法性;
PS:网上有些文章建议这样配置 Nginx,其实并不合理:
proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $remote_addr;
这样配置之后,安全性确实提高了,但是也导致请求到达 Nginx 之前的所有代理信息都被抹掉,无法为真正使用代理的用户提供更好的服务。还是应该弄明白这中间的原理,具体场景具体分析。
proxy_intercept_errors on; #如果被代理服务器返回的状态码为400或者大于400,设置的error_page配置起作用。默认为off。
error_page 404 https://www.baidu.com; #错误页
如果我们的代理只允许接受get,post请求方法的一种
proxy_method get; #支持客户端的请求方法。post/get;
如果你的nginx服务器给2台web服务器做代理,负载均衡算法采用轮询,那么当你的一台机器web程序iis关闭,也就是说web不能访问,那么nginx服务器分发请求还是会给这台不能访问的web服务器,如果这里的响应连接时间过长,就会导致客户端的页面一直在等待响应,对用户来说体验就打打折扣,这里我们怎么避免这样的情况发生呢。这里我配张图来说明下问题。
如果负载均衡中其中web2发生这样的情况,nginx首先会去web1请求,但是nginx在配置不当的情况下会继续分发请求道web2,然后等待web2响应,直到我们的响应时间超时,才会把请求重新分发给web1,这里的响应时间如果过长,用户等待的时间就会越长。
下面的配置是解决方案之一。
proxy_connect_timeout 1; #nginx服务器与被代理的服务器建立连接的超时时间,默认60秒
proxy_read_timeout 1; #nginx服务器想被代理服务器组发出read请求后,等待响应的超时间,默认为60秒。
proxy_send_timeout 1; #nginx服务器想被代理服务器组发出write请求后,等待响应的超时间,默认为60秒。
proxy_ignore_client_abort on; #客户端断网时,nginx服务器是否终端对被代理服务器的请求。默认为off。
通常系统出于安全考虑,需要进行权限(账号、密码)和IP白名单控制。如何获取访问来源真实的IP,如果公司网络入口设置负载,自己系统设置nginx代理等操作,会使你达到目的不那么简单直接。
通常情况下我们使用request.getRemoteAddr()就可以获取到客户端ip,但是当我们使用了nginx作为反向代理后,由于在客户端和web服务器之间增加了中间层,因此web服务器无法直接拿到客户端的ip,通过$remote_addr变量拿到的将是反向代理服务器的ip地址。如果我们想要在web端获得用户的真实ip,就必须在nginx这里作一个赋值操作,如下:
proxy_set_header X-real-ip $remote_addr;
其中这个X-real-ip是一个自定义的变量名,这样用户的真实ip就被放在X-real-ip这个变量里了,然后,在web端可以这样获取:request.getAttribute("X-real-ip")。但是如果中间经过N次代理过来的请求,X-real-ip就只能获得到前一层代理的IP(10.6.61.14)了,下面是我的解决方案:
红色部分IP是使用X-Forwarded-For(简称XFF头)获取的:,它代表客户端,也就是HTTP的请求端真实的IP,只有在通过了HTTP 代理或者负载均衡服务器时才会添加该项(没有经过的获取为空)标准格式如下:
X-Forwarded-For: client1, proxy1, proxy2
从标准格式可以看出,X-Forwarded-For头信息可以有多个,中间用逗号分隔,第一项为真实的客户端ip,剩下的就是曾经经过的代理或负载均衡的ip地址,经过几个就会出现几个。
我的Nginx具体配置如下:
关于参数含义:
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
意思是增加(不是覆盖)一个$proxy_add_x_forwarded_for到X-Forwarded-For里去。
举个例子,有一个web应用,在它之前通过了两个nginx转发。在第一台nginx中,使用
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
现在的$proxy_add_x_forwarded_for变量的"X-Forwarded-For"部分是空的,所以只有$remote_addr,而$remote_addr的值是用户的ip,于是赋值以后,X-Forwarded-For变量的值就是用户的真实的ip地址了。
到了第二台nginx,使用
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
现在的$proxy_add_x_forwarded_for变量,X-Forwarded-For部分包含的是用户的真实ip,$remote_addr部分的值是上一台nginx的ip地址,于是通过这个赋值以后现在的X-Forwarded-For的值就变成了“用户的真实ip,第一台nginx的ip”。
所以我在程序中使用request.getHeader("x-forwarded-for").toString().split(",")[0]就能获取到访问客户的真实IP,不用担心前面有几层转发啦。
exp qq/1qqq BUFFER=640000 FILE=/oracleq/appq/oracleq/newq.DMP OWNER=qq
upstream tomcat_server { server IP地址:端口; }
upstream authority_server { server IP地址:端口; }
if ( $request_uri ~ "^\/itoo-basic" )
{
proxy_pass http://tomcat_server;
}
if ( $request_uri ~ "^\/itoo-authority" )
{
proxy_pass http://authority_server;
}
在Tomcat的bin目录中执行
chmod u+x *.sh
摘要: 二、安装Nginx1、上传nginx-0.7.63.tar.gz至/usr/local 2、执行如下命令解压nginx:1.#cd /usr/local2.#tar zxvf nginx-0.7.63.tar.gz3、编译安装nginx1.#cd nginx-0.7.632.#./configure --with-http_stub_status_module --with-...
阅读全文
//连接
connect /as sysdba
1.创建表空间和用户并为用户指定表空间
//创建临时表空间
create temporary tablespace user_temp tempfile 'D:oracleoradatauser_temp.dbf' size 50m autoextend on next 50m maxsize 20480m extent management local;
(注:user_temp是临时表空间的名称。)
//创建数据表空间lportal
create tablespace lportal logging datafile 'D:oracleoradatalportal.dbf' size 100m autoextend on next 50m extent management local;
(注:lportal是数据表空间的名称。)
//创建用户lportal并指定表空间
create user lportal identified by lportal default tablespace lportal_db temporary tablespace user_temp;
(注:第一个lportal是用户名,第二个lportal是密码;lportal_db是数据表空间名称,user_temp是临时表空间名称。)
//为lportal用户授权
grant connect,resource,dba to lportal;
2.数据备份(导入导出数据)
//导入数据
imp lportal/lportal@orcl file=d:lportal20121109.dmp full=Y
//导出数据
exp lportal/lportal@orcl file=D:lportal20121109.dmp
(数据的导入与导出,在进入到黑窗口后直接输入上列语句,不需要进入sqlplus)
3.删除用户及表空间
//删除用户以及用户所有的对象
drop user lportal cascade;
//删除表空间与表空间文件(注意:如果在创建表空间的时候带有双引号,则删除的时候也要带上)
DROP TABLESPACE "stu_new" INCLUDING CONTENTS AND DATAFILES;
前提:删除表空间之前要确认该表空间没有被其他用户使用之后再做删除
drop tablespace zfmi including contents and datafiles cascade onstraints;
//including contents 删除表空间中的内容,如果删除表空间之前表空间中有内容,而未加此参数,表空间删不掉,所以习惯性的加此参数
//including datafiles 删除表空间中的数据文件
//cascade constraints 同时删除tablespace中表的外键参照
4.查询表空间和查询用户
//查询所有表空间名称
select tablespace_name from dba_tablespaces;
//查看表空间的名称和状态
select tablespace_name,status from dba_tablespaces;
//查询当前表空间属性
select * from dba_tablespaces where tablespace_name='mtgyd';
//查询所有用户
select username from dba_users;
1、在某一目录下面创建存放表空间的目录,并赋予权限 chmod 777 文件 或者
sudo chmod -R 777 文件2、创建临时表空间 create temporary tablespace USER_TEMP tempfile '/app1/orac1lenamespase/newn1amespase/USER_TEMP1.bdf' size 5120m reuse autoextend on next 20m maxsize unlimited;
3.创建表空间 create tablespace ZHFXBEMS1 datafile '/app1/ora1clenamespase/newnames1pase/ZHFXBEMS1.dbf' size 20480M reuse autoextend on next 40M maxsize unlimited default storage(initial 128k next 128k minextents 2 maxextents unlimited);
4、创建用户和指定使用的表空间 create user qqidentified by 1 default tablespace ZHFXBEMSq temporary tablespace USER_TEMPq;
5.赋予权限
grant dba to qq;
grant connect,resource to qq;
grant select any table to qq;
grant delete any table to qq;
grant update any table to qq;
grant insert any table to qq;
当多线程访问资源时,每条线程的数据变量都是不一样的,线程间的数据需要做到独立,不能相互共享,例如,数据库中常见的转账业务,两次转出和转入操作,不能共享数据,还要注意线程安全。
package com.yjw.thread;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
public class ThreadScopeShareData {
static class A{
public void get(){
System.out.println(" A="+Thread.currentThread().getName()+",data="+map.get(Thread.currentThread()));
}
}
static class B{
public void get(){
System.out.println(" B="+Thread.currentThread().getName()+",data="+map.get(Thread.currentThread()));
}
}
static Map<Thread, Integer> map = new HashMap<Thread, Integer>();
public static void main(String[] args) {
for (int i = 0; i < 2; i++) {
new Thread(new Runnable() {
public void run() {
int data=new Random().nextInt();
System.out.println(Thread.currentThread().getName()+",data="+data);
map.put(Thread.currentThread(), data);
new A().get();new B().get();
}
}).start();
}
}
}
当使用了mvc:resources标签后,必须使用 <mvc:annotation-driven/>标签,就不会请求controller失败了。
public class Man {
private String id;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public void man() {
System.out.println("man");
}
}
public class TestMan {
//值传递传递的是值的副本
public static int getInt(int i){
i=4;
return i;
}
//引用传递,传递的是对象的引用,指向的还是原来的对象
public static Man getMan(Man man){
man.setId("111");
return man;
}
public static String getS(String s){
return s="111";
}
public static void main(String[] args) {
int i=1;
TestMan.getInt(i);
System.out.println(i);
Man man = new Man();
man.setId("222");
TestMan.getMan(man);
System.out.println(man.getId());
String s="222";
TestMan.getS(s);
System.out.println(s);
}
}
package com.yjw.thread;
public class Test2 {
static class Businis {
boolean f = false;// true sub执行,false main执行
public synchronized void sub(int i) {
if (!f) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for (int j = 1; j <= 10; j++) {
System.out.println("sub=" + j + ",loop=" + i);
}
f = false;
this.notify();
}
public synchronized void main(int i) {
if (f) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for (int j = 1; j <= 100; j++) {
System.out.println("main=" + j + ",loop=" + i);
}
f = true;
this.notify();
}
}
public static void main(String[] args) {
final Businis businis = new Businis();
for (int i = 1; i <= 50; i++) {
businis.main(i);
businis.sub(i);
}
}
}
@org.junit.Test
public void test2(){
new Thread( new Runnable() {
public void run() {
System.out.println(2);
}
}){
public void run() {
System.out.println(1);
};
}.start();
}
线程重写了run方法,又传入了新的线程,此线程只执行重写了run方法的方法,因为根据面向对象的原则,子类重写了父类的方法,只执行子类的方法。
一个页面同时触发ajax请求的次数不能过多,同时触发的次数不要超过6个,不然过多的ajax会被浏览器阻塞,不能实现异步请求。
负载均衡时,如果客户端访问出现404的情况时,有可能是负载均衡映射到了空的服务造成的,需要检查负载均衡对应的后台主机是否存在。
1、
- create user aaaaidentified by 123aaa;
2、
grant connect, resource to aaaa;
3、
grant create session to aaaa;
在DAO文件中,通过sessionFactory.getCurrentSession()来获取会话,报异常:org.hibernate.HibernateException: createQuery is not valid without active transaction。经过实验,发现将Hibernate的配置文件中的<property name="current_session_context_class">thread</property>属性去掉就好了。原来"current_session_context_class"属性的意思是,设置当前会话的上下文环境,如果设置为thread,那么同一线程则共享同一session会话。因此通过getCurrentSession()得到的session,是同一线程上的session,而不是Spring管理的那个能够自动开启事务的session。去除掉该属性就好了
2. 泛型类:泛型只在编译时期有效,编译后的字节码文件中不存在有泛型信息!
1. 泛型方法:
public class GenericDemo {
// 定义泛型方法
public <K,T> T save(T t,K k) {
return null;
}
// 测试方法
@Test
public void testMethod() throws Exception {
// 使用泛型方法: 在使用泛型方法的时候,确定泛型类型
save(1.0f, 1);
}
}
2. 泛型类:
public class GenericDemo<T> {
// 定义泛型方法
public <K> T save(T t,K k) {
return null;
}
public void update(T t) {
}
// 测试方法
@Test
public void testMethod() throws Exception {
// 泛型类: 在创建爱泛型类对象的时候,确定类型
GenericDemo<String> demo = new GenericDemo<String>();
demo.save("test", 1);
}
}
3. 泛型接口:
/**
* 泛型接口
* @author Jie.Yuan
*
* @param <T>
*/
public interface IBaseDao<T> {
void save(T t );
void update(T t );
}
泛型接口类型确定: 实现泛型接口的类也是抽象,那么类型在具体的实现中确定或创建泛型类的时候确定。
泛型的反射
/**
* 所有dao的公用的方法,都在这里实现
* @author Jie.Yuan
*
*/
public class BaseDao<T>{
// 保存当前运行类的参数化类型中的实际的类型
private Class clazz;
// 表名
private String tableName;
// 构造函数: 1. 获取当前运行类的参数化类型; 2. 获取参数化类型中实际类型的定义(class)
public BaseDao(){
// this 表示当前运行类 (AccountDao/AdminDao)
// this.getClass() 当前运行类的字节码(AccountDao.class/AdminDao.class)
// this.getClass().getGenericSuperclass(); 当前运行类的父类,即为BaseDao<Account>
// 其实就是“参数化类型”, ParameterizedType
Type type = this.getClass().getGenericSuperclass();
// 强制转换为“参数化类型” 【BaseDao<Account>】
ParameterizedType pt = (ParameterizedType) type;
// 获取参数化类型中,实际类型的定义 【new Type[]{Account.class}】
Type types[] = pt.getActualTypeArguments();
// 获取数据的第一个元素:Accout.class
clazz = (Class) types[0];
// 表名 (与类名一样,只要获取类名就可以)
tableName = clazz.getSimpleName();
}
/**
* 主键查询
* @param id 主键值
* @return 返回封装后的对象
*/
public T findById(int id){
/*
* 1. 知道封装的对象的类型
* 2. 表名【表名与对象名称一样, 且主键都为id】
*
* 即,
* ---》得到当前运行类继承的父类 BaseDao<Account>
* ----》 得到Account.class
*/
String sql = "select * from " + tableName + " where id=? ";
try {
return JdbcUtils.getQuerrRunner().query(sql, new BeanHandler<T>(clazz), id);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
/**
* 查询全部
* @return
*/
public List<T> getAll(){
String sql = "select * from " + tableName ;
try {
return JdbcUtils.getQuerrRunner().query(sql, new BeanListHandler<T>(clazz));
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
<!-- Log4j配置 -->
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>classpath:config/log4j.properties</param-value>
</context-param>
<context-param>
<param-name>log4jRefreshInterval</param-name>
<param-value>60000</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.util.Log4jConfigListener
</listener-class>
</listener>
<!-- end -->
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
配置的顺序不能乱!
package com.annotation;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={ FIELD, METHOD})
public @interface Column {
String ColumnName();
}
package com.annotation;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={ FIELD, METHOD})
public @interface Id {
}
package com.annotation;
import static java.lang.annotation.ElementType.TYPE;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={ TYPE})
public @interface Table {
String tableName();
}
package com;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import com.annotation.Column;
import com.annotation.Id;
import com.annotation.Table;
public class BaseDao<T,Pk> {
private Class<T> persistentClass;
@SuppressWarnings("unused")
private Class<Pk> persistentPK;
private String tableName;//表名称
private String id;//主键
public BaseDao() {
ParameterizedType ptype=(ParameterizedType) this.getClass().getGenericSuperclass();
Type[] types = ptype.getActualTypeArguments();
for (Type type : types) {
System.out.println(type.toString());
}
this.persistentPK = (Class<Pk>) types[1];
this.persistentClass = (Class<T>) types[0];
Table table = this.persistentClass.getAnnotation(Table.class);
tableName=table.tableName();
Field[] fields = this.persistentClass.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
Id annotationId = field.getAnnotation(Id.class);
if(annotationId != null){
Column annotationCo = field.getAnnotation(Column.class);
id=annotationCo.ColumnName();
break;
}
}
}
public T getT(T t){
System.out.println(tableName);
System.out.println(id);
return t;
}
}
package com;
import com.annotation.Column;
import com.annotation.Id;
import com.annotation.Table;
@Table(tableName = "t_user")
public class User {
@Id
@Column(ColumnName = "uid")
private String id="1";
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public User(String id) {
super();
this.id = id;
System.out.println("有参数");
}
public User() {
System.out.println("没有参数");
}
}
package com;
public class UserDao extends BaseDao<User, String>{
}
package com;
import java.util.List;
public class App<T> {
/**
* list必须都是Number的子类
* @param list
*/
public void get1(List<? extends Number> list){
System.out.println(list.size());
}
/**
* list必须都是String的父类
* @param list
*/
public void get2(List<? super String> list){
System.out.println(list.size());
}
}
摘要: 一、秒杀业务为什么难做1)im系统,例如qq或者微博,每个人都读自己的数据(好友列表、群列表、个人信息);2)微博系统,每个人读你关注的人的数据,一个人读多个人的数据;3)秒杀系统,库存只有一份,所有人会在集中的时间读和写这些数据,非常多个人同时读一个数据。 例如:小米手机每周二的秒杀,可能手机只有1万部,但瞬时进入的流量可能是几百几千万。又例如:12306抢票,票是有限的,库存一份,瞬...
阅读全文
jdk的动态代理对象和目标对象要实现同一个接口。
public class Classes implements Serializable{
private Long cid;
public Long getCid() {
return cid;
}
public void setCid(Long cid) {
this.cid = cid;
}
public String getCname() {
return cname;
}
public void setCname(String cname) {
this.cname = cname;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
private String cname;
private String description;
}
public interface ClassesDao {
public void saveClasses(Classes classes);
}
public class ClassesDaoImpl implements ClassesDao{
@Override
public void saveClasses(Classes classes) {
System.out.println("保存");
}
}
public class MyTransaction {
public void beginTransaction(){
System.out.println("开始事务");
}
public void commit(){
System.out.println("提交事务");
}
}
public class ClassesDaoInterceptor implements InvocationHandler{
private Object target;
private MyTransaction myTransaction;
public ClassesDaoInterceptor(Object target,MyTransaction myTransaction){
this.target = target;
this.myTransaction = myTransaction;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println(proxy.getClass().getName());
if(method.getName().equals("saveClasses")||
method.getName().equals("updateClasses")){
this.myTransaction.beginTransaction();//֪ͨ
method.invoke(this.target, args);//Ŀ�귽��
this.myTransaction.commit();
}else{
method.invoke(this.target, args);
}
return null;
}
}
public class ClassesDaoTest {
public static void testSaveClasses(){
Object target = new ClassesDaoImpl();
MyTransaction myTransaction = new MyTransaction();
ClassesDaoInterceptor interceptor = new ClassesDaoInterceptor(target, myTransaction);
ClassesDao proxyDao = (ClassesDao) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), interceptor);
Classes classes = new Classes();
classes.setCname("aaaa");
proxyDao.saveClasses(classes);
}
public static void main(String[] args) {
testSaveClasses();
}
}
spring的事务也是动态代理实现的,当一个服务类里的一个实现了服务接口的方法中调用另一个服务方法,第二个服务方法不会加入到事务中,因为这种调用方式不是被代理对象调用,而是实际目标对象调用,不会产生代理对象,所以第二个服务方法不会加入到事务中,如果想实现这种操作,需要先得到aop的代理对象,AopContext.currentProxy();,得到服务接口,进行调用服务方法。spring的事务代理是cglib实现的,只能代理访问接口中的方法。
cglib的动态生成的代理对象是目标类的子类。
public class Classes implements Serializable{
private Long cid;
public Long getCid() {
return cid;
}
public void setCid(Long cid) {
this.cid = cid;
}
public String getCname() {
return cname;
}
public void setCname(String cname) {
this.cname = cname;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
private String cname;
private String description;
}
public interface ClassesDao {
public void saveClasses(Classes classes);
}
public class ClassesDaoImpl implements ClassesDao{
@Override
public void saveClasses(Classes classes) {
System.out.println("保存");
}
}
public class ClassesDaoInterceptor implements MethodInterceptor {
private Object target;
private MyTransaction myTransaction;
public ClassesDaoInterceptor(Object target, MyTransaction myTransaction) {
this.target = target;
this.myTransaction = myTransaction;
}
public Object create() {
Enhancer en = new Enhancer();
en.setSuperclass(target.getClass());
en.setCallback(this);
return en.create();
}
@Override
public Object intercept(Object proxy, Method method, Object[] args,
MethodProxy arg3) throws Throwable {
System.out.println(proxy.getClass().getName());
System.out.println(arg3.getSuperName());
if (method.getName().equals("saveClasses")
|| method.getName().equals("updateClasses")) {
this.myTransaction.beginTransaction();// ֪ͨ
method.invoke(this.target, args);// Ŀ�귽��
this.myTransaction.commit();
} else {
method.invoke(this.target, args);
}
return null;
}
}
public class MyTransaction {
public void beginTransaction(){
System.out.println("开始事务");
}
public void commit(){
System.out.println("提交事务");
}
}
public class ClassesDaoTest {
public static void testSaveClasses(){
Object dao = new ClassesDaoImpl();
MyTransaction myTransaction = new MyTransaction();
ClassesDaoInterceptor interceptor = new ClassesDaoInterceptor(dao, myTransaction);
ClassesDaoImpl proxyDao= (ClassesDaoImpl) interceptor.create();
Classes classes = new Classes();
classes.setCname("aaaa");
proxyDao.saveClasses(classes);
}
public static void main(String[] args) {
testSaveClasses();
}
}
jdk的动态代理模式的目标类和动态生成的代理类都要实现同一个接口。
public interface MoveAble {
void move();
}
public interface InvocationHandler {
public void invoke(Object o, Method m);
}
public class Tank1 implements MoveAble{
@Override
public void move() {
System.out.println("moving");
}
}
public class TimeHandler implements InvocationHandler{
private Object target;
public TimeHandler(Object target) {
super();
this.target = target;
}
@Override
public void invoke(Object o, Method m) {
long start = System.currentTimeMillis();
System.out.println("starttime:" + start);
System.out.println(o.getClass().getName());
try {
m.invoke(target);
} catch (Exception e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println("time:" + (end-start));
}
}
public class Proxy {
public static Object newProxyInstance(Class infce, InvocationHandler invocationHandler) throws Exception { //JDK6 Complier API, CGLib, ASM
String methodStr = "";
String rt = "\r\n";
Method[] methods = infce.getMethods();
for(Method m : methods) {
Class<?> returnType = m.getReturnType();
methodStr += "@Override" + rt +
"public "+returnType+" " + m.getName() + "() {" + rt +
" try {" + rt +
" Method md = " + infce.getName() + ".class.getMethod(\"" + m.getName() + "\");" + rt +
" h.invoke(this, md);" + rt +
" }catch(Exception e) {e.printStackTrace();}" + rt +
"}";
}
String src =
"package proxy.tank;" + rt +
"import java.lang.reflect.Method;" + rt +
"public class $Proxy1 implements " + infce.getName() + "{" + rt +
" public $Proxy1(InvocationHandler h) {" + rt +
" this.h = h;" + rt +
" }" + rt +
" proxy.tank.InvocationHandler h;" + rt +
methodStr +
"}";
String fileName =
"d:/src/proxy/tank/$Proxy1.java";
File f = new File(fileName);
FileWriter fw = new FileWriter(f);
fw.write(src);
fw.flush();
fw.close();
//compile
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null);
Iterable units = fileMgr.getJavaFileObjects(fileName);
CompilationTask t = compiler.getTask(null, fileMgr, null, null, null, units);
t.call();
fileMgr.close();
//load into memory and create an instance
URL[] urls = new URL[] {new URL("file:/" + "d:/src/")};
URLClassLoader ul = new URLClassLoader(urls);
Class c = ul.loadClass("proxy.tank.$Proxy1");
System.out.println(c);
Constructor ctr = c.getConstructor(InvocationHandler.class);
Object m = ctr.newInstance(invocationHandler);
return m;
}
}
public class Client {
public static void main(String[] args) throws Exception {
Tank1 t = new Tank1();
InvocationHandler h = new TimeHandler(t);
MoveAble m = (MoveAble)Proxy.newProxyInstance(MoveAble.class, h);
m.move();
}
}
public interface MoveAble {
void move();
}
public class Tank1 implements MoveAble{
@Override
public void move() {
System.out.println("moving");
}
}
/**
*
* 聚合
*
*/
public class TankTime3 implements MoveAble{
private MoveAble t;
public TankTime3(){}
public TankTime3(MoveAble t){
this.t=t;
}
@Override
public void move() {
long s = System.currentTimeMillis();
t.move();
long e = System.currentTimeMillis();
System.out.println(e-s);
}
}
public class Test {
public static void main(String[] args) {
Tank1 t =new Tank1();
TankTime3 tt = new TankTime3(t);
tt.move();
}
}
使用策略模式自定义对象排序和比较属性值排序的例子
/**
*
* 实体类的接口
*
*/
public interface DongWu {
public int getAge();
public void setAge(int age) ;
public int getHigh();
public void setHigh(int high) ;
}
/**
*
* 排序接口
*
*/
public interface MyComparator {
int comparatorTo(Object object);
}
/**
*
* 具体的排序接口,和具体的实体类对象无关
*
*/
public interface TypeComparator {
int comparatorTo(Object object1,Object object2);
}
/**
*
* 按照年纪倒叙排序
*
*/
public class AgeDescTypeComparator implements TypeComparator {
@Override
public int comparatorTo(Object object1, Object object2) {
DongWu c1 = (DongWu) object1;
DongWu dw = (DongWu) object2;
if (c1.getAge() > dw.getAge()) {
return -1;
} else if (c1.getAge() < dw.getAge()) {
return 1;
}
return 0;
}
}
/**
*
* 按照年纪正叙排序
*
*/
public class AgeTypeComparator implements TypeComparator {
@Override
public int comparatorTo(Object object1, Object object2) {
DongWu c1 = (DongWu) object1;
DongWu dw = (DongWu) object2;
if (c1.getAge() > dw.getAge()) {
return 1;
} else if (c1.getAge() < dw.getAge()) {
return -1;
}
return 0;
}
}
public class Cat implements MyComparator,DongWu{
private int age;
private int high;
private TypeComparator typeComparator =new AgeDescTypeComparator();
public Cat(){}
public Cat(int age){
this.age=age;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getHigh() {
return high;
}
public void setHigh(int high) {
this.high = high;
}
@Override
public int comparatorTo(Object object) {
DongWu cat = (DongWu) object;
return typeComparator.comparatorTo(this, cat);
}
}
public class Dog implements MyComparator,DongWu{
private int age;
private int high;
private TypeComparator typeComparator =new AgeDescTypeComparator();
public Dog(){}
public Dog(int age){
this.age=age;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getHigh() {
return high;
}
public void setHigh(int high) {
this.high = high;
}
@Override
public int comparatorTo(Object object) {
DongWu d = (DongWu) object;
return typeComparator.comparatorTo(this, d);
}
}
public class DataSorter {
public static void sort(MyComparator[] arr){
for (int i = arr.length; i >0 ; i--) {
for(int j=0;j<i-1;j++){
MyComparator m1=arr[j];
MyComparator m2= arr[j+1];
if(m1.comparatorTo(m2)==1){
swap(arr,j,j+1);
}
}
}
}
private static void swap(Object[] arr, int j, int i) {
Object temp =arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
public interface Iterator {
Object next();
boolean hasNext();
}
public interface Collection {
void add(Object data);
int size();
Iterator iterator();
}
//集合
public class MyArrayList implements Collection{
private Object[] array = new Object[10];
private int index=0;//数值当前可以放值的下标
public void add( Object obj){
if(index==array.length){
Object[] newArray = new Object[array.length*2];
System.arraycopy(array, 0, newArray, 0, index);
array=newArray;
}
array[index]=obj;
index++;
}
public int size(){
return index;
}
@Override
public Iterator iterator() {
return new Aaa();
}
private class Aaa implements Iterator{
private int c=0;
@Override
public boolean hasNext() {
if(c<index){
return true;
}else{
return false;
}
}
@Override
public Object next() {
Object object = array[c];
c++;
return object;
}
}
public static void main(String[] args) {
MyArrayList arr = new MyArrayList();
for (int i = 0; i < 20; i++) {
arr.add(new Object());
}
System.out.println(arr.size());
Iterator iterator = arr.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
//链表
public class MyNode {
private Object data;
private MyNode nextNode;
public MyNode(Object data,MyNode nextNode){
this.data=data;
this.nextNode=nextNode;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public MyNode getNextNode() {
return nextNode;
}
public void setNextNode(MyNode nextNode) {
this.nextNode = nextNode;
}
}
public class MyLinkTable implements Collection{
private MyNode head;
private MyNode tail;
private int size = 0;
public void add(Object data) {
MyNode n = new MyNode(data, null);
if (head == null) {
head = n;
tail = n;
}
tail.setNextNode(n);
tail = n;
size++;
}
public int size() {
return size;
}
public MyNode getHead() {
return head;
}
public void setHead(MyNode head) {
this.head = head;
}
public MyNode getTail() {
return tail;
}
public void setTail(MyNode tail) {
this.tail = tail;
}
@Override
public Iterator iterator() {
return new Aaa();
}
private class Aaa implements Iterator{
private int c=0;
MyNode node=null;
@Override
public boolean hasNext() {
for (int i = 0; i <=c; i++) {
if(i==0){
node = head;
}else{
node = node.getNextNode();
}
}
if(node==null){
return false;
}else{
return true;
}
}
@Override
public Object next() {
for (int i = 0; i <=c; i++) {
if(i==0){
node = head;
}else{
node = node.getNextNode();
}
}
c++;
return node;
}
}
public static void main(String[] args) {
MyLinkTable node = new MyLinkTable();
node.add(1);
node.add(2);
node.add(3);
Iterator iterator = node.iterator();
while(iterator.hasNext()){
MyNode node1= (MyNode) iterator.next();
System.out.println(node1.getData());
}
}
}
装饰模式指的是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
public interface ICake {
public float cost();
}
public abstract class CakeDecorator implements ICake{
}
public class MilkCake implements ICake{
@Override
public float cost() {
return 100f;
}
}
public class Berry extends CakeDecorator {
private ICake cake;
public Berry(ICake cake) {
this.cake = cake;
}
@Override
public float cost() {
float berryPrice = 5f;
return cake.cost() + berryPrice;
}
}
public class Chocolate extends CakeDecorator{
private ICake cake;
public Chocolate(ICake cake) {
this.cake = cake;
}
@Override
public float cost() {
float chocolatePrice = 25f;
return cake.cost() + chocolatePrice;
}
}
public class Test {
public static void main(String[] args) throws FileNotFoundException {
MilkCake mc = new MilkCake();
Berry b = new Berry(mc);
Chocolate c = new Chocolate(b);
System.out.println("" + c.cost());
}
}
观察者模式(有时又被称为发布(publish )-订阅(Subscribe)模式、模型-视图(View)模式、源-收听者(Listener)模式或从属者模式)是软件设计模式的一种。在此种模式中,一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实现事件处理系统。
public interface Observer {
public void update(int low,int heigh,String weather);
void removeSubject();
}
public interface Subject {
public void registerObserver(Observer observer);
public void removeObserver(Observer observer);
public void notifyObserver();
}
public class Android implements Observer{
public Android(){}
private Subject subject;
public Android(Subject subject) {
this.subject = subject;
this.subject.registerObserver(this);
}
@Override
public void update(int low, int heigh, String weather) {
System.out.println("Android" + low + "," + heigh + "," + weather);
}
public void removeSubject() {
subject.removeObserver(this);
}
}
public class IPad implements Observer{
private Subject subject;
public IPad(){}
public IPad(Subject subject) {
this.subject = subject;
subject.registerObserver(this);
}
@Override
public void update(int low, int heigh, String weather) {
System.out.println("IPad " + low + "," + heigh + "," + weather);
}
public void removeSubject() {
subject.removeObserver(this);
}
}
public class WeatherData implements Subject{
private int low;
private int heigh;
private String weather;
private List<Observer> observerList = new ArrayList<Observer>();
public void setData(int low,int heigh,String weather) {
this.low = low;
this.heigh = heigh;
this.weather = weather;
notifyObserver();
}
public int getLow() {
return low;
}
public int getHeigh() {
return heigh;
}
public String getWeather() {
return weather;
}
@Override
public void registerObserver(Observer observer) {
if(!observerList.contains(observer)) {
observerList.add(observer);
}
}
@Override
public void removeObserver(Observer observer) {
if(observerList.contains(observer)) {
observerList.remove(observer);
}
}
@Override
public void notifyObserver() {
for(Observer o : observerList) {
o.update(getLow(), getHeigh(), getWeather());
}
}
}
public class Test {
public static void main(String[] args) {
WeatherData wd = new WeatherData();
Android android = new Android(wd);
//android.removeSubject();
IPad ipad = new IPad(wd);
//ipad.removeSubject();
wd.setData(2, 23, "---");
}
}
public interface Filter {
void doFilter(Request request, Response response, FilterChain chain);
}
public class FilterChain implements Filter {
List<Filter> filters = new ArrayList<Filter>();
int index = 0;
public FilterChain addFilter(Filter f) {
this.filters.add(f);
return this;
}
@Override
public void doFilter(Request request, Response response, FilterChain chain) {
if(index == filters.size()) return ;
Filter f = filters.get(index);
index ++;
f.doFilter(request, response, chain);
}
}
public class HTMLFilter implements Filter {
@Override
public void doFilter(Request request, Response response, FilterChain chain) {
//process the html tag <>
request.requestStr = request.requestStr.replace('<', '[')
.replace('>', ']') + "---HTMLFilter()";
chain.doFilter(request, response, chain);
response.responseStr += "---HTMLFilter()";
}
}
public class SesitiveFilter implements Filter {
@Override
public void doFilter(Request request, Response response, FilterChain chain) {
request.requestStr = request.requestStr.replace("", "")
.replace("", "") + "---SesitiveFilter()";
chain.doFilter(request, response, chain);
response.responseStr += "---SesitiveFilter()";
}
}
public class Request {
String requestStr;
public String getRequestStr() {
return requestStr;
}
public void setRequestStr(String requestStr) {
this.requestStr = requestStr;
}
}
public class Response {
String responseStr;
public String getResponseStr() {
return responseStr;
}
public void setResponseStr(String responseStr) {
this.responseStr = responseStr;
}
}
public class Main {
/**
* @param args
*/
public static void main(String[] args) {
String msg = "";
Request request = new Request();
request.setRequestStr(msg);
Response response = new Response();
response.setResponseStr("response");
FilterChain fc = new FilterChain();
fc.addFilter(new HTMLFilter())
.addFilter(new SesitiveFilter())
;
fc.doFilter(request, response, fc);
System.out.println(request.getRequestStr());
System.out.println(response.getResponseStr());
}
}
单例模式分为恶汉式,就是直接在类中new出,直接返回对象,懒汉式是在调用对象时判断对象是否是null,如果null,先new出,再返回,否则直接返回对象,但是这种方式会线程不安全,所以采用双重检查的设计思想,保证线程安全。
package singleton;
public class Teacher3 {
private Teacher3(){}
private static Teacher3 t=null;
public static Teacher3 getTeacher3(){
if(t==null){
synchronized (Teacher3.class) {
if(t==null){
t=new Teacher3();
}
}
}
return t;
}
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
第二种方式,内部类方式
package test;
/**
* 在多线程中使用单例对象的设计模式,内部类
*
*/
public class InnerSingleton {
private static class Singleton{
private static Singleton s=new Singleton();
public void add(){
}
}
public static Singleton getSingleton(){
return Singleton.s;
}
public static void main(String[] args) {
Singleton singleton = InnerSingleton.getSingleton();
singleton.add();
}
}
具体的水果工厂实现类 | 具体的苹果实现类 | 具体的香蕉实现类 | 具体的枣实现类 |
中国水果工厂实现类 | 中国苹果 | 中国香蕉 | 中国枣 |
日本水果工厂实现类 | 日本苹果 | 日本香蕉 | 日本枣 |
以此类推,在工厂的接口中创建所有水果的方法声明。
public interface IFruit {
public void get();
}
public abstract class AbstractApple implements IFruit{
public abstract void get();
}
public abstract class AbstractBanana implements IFruit{
public abstract void get();
}
public interface IFruitFactory {
public IFruit getApple();
public IFruit getBanana();
}
public class NorthApple extends AbstractApple {
public void get() {
System.out.println("北方苹果");
}
}
public class NorthBanana extends AbstractBanana {
public void get() {
System.out.println("北方香蕉");
}
}
public class NorthFruitFactory implements IFruitFactory {
public IFruit getApple() {
return new NorthApple();
}
public IFruit getBanana() {
return new NorthBanana();
}
}
public class SouthApple extends AbstractApple {
public void get() {
System.out.println("南方苹果");
}
}
public class SouthBanana extends AbstractBanana {
public void get() {
System.out.println("南方香蕉");
}
}
public class SouthFruitFactory implements IFruitFactory {
public IFruit getApple() {
return new SouthApple();
}
public IFruit getBanana() {
return new SouthBanana();
}
}
package methodFactory;
public interface People {
void say();
}
package methodFactory;
public class Man implements People{
public void say() {
System.out.println("男人");
}
}
package methodFactory;
public class Woman implements People{
public void say() {
System.out.println("女人");
}
}
package methodFactory;
public interface PeopleFactory {
People create();
}
package methodFactory;
public class ManFactory implements PeopleFactory{
public People create() {
return new Man();
}
}
package methodFactory;
public class WomanFactory implements PeopleFactory{
public People create() {
return new Woman();
}
}
package methodFactory;
public class Test {
public static void main(String[] args) {
PeopleFactory manf= new ManFactory();
People man = manf.create();
man.say();
PeopleFactory wf= new WomanFactory();
People w = wf.create();
w.say();
}
}
好处是新增加的子类不会影响以前的实现,代码的扩展性好。
package simpleFactory;
public interface People {
void say();
}
package simpleFactory;
public class Man implements People{
public void say() {
System.out.println("男人");
}
}
package simpleFactory;
public class Woman implements People{
public void say() {
System.out.println("女人");
}
}
package simpleFactory;
public class SimpleFactory {
public static People create(String className) throws ClassNotFoundException, InstantiationException, IllegalAccessException{
Class class1 = Class.forName(className);
return (People) class1.newInstance();
}
}
package simpleFactory;
public class Test {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
People man = SimpleFactory.create("simpleFactory.Man");
People woman = SimpleFactory.create("simpleFactory.Woman");
man.say();
woman.say();
}
}
/**
* 处理接收任务
*/
@Test
public void test4(){
String executionId = "2101";
pe.getRuntimeService().signal(executionId );
}
由于接收任务在任务表中没有任务,所有可以传递流程实例的ID或者执行ID处理接收任务。
package com.task.group;
import java.util.List;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.DeploymentBuilder;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.junit.Test;
/**
* 公共任务测试
*
*
*/
public class GroupTaskTest {
static ProcessEngine pe =null;
static{
ProcessEngineConfiguration conf = ProcessEngineConfiguration.
createStandaloneProcessEngineConfiguration();
conf.setJdbcDriver("com.mysql.jdbc.Driver");
conf.setJdbcUrl("jdbc:mysql://localhost:3306/activiti02?useUnicode=true&characterEncoding=UTF-8");
conf.setJdbcUsername("root");
conf.setJdbcPassword("root");
conf.setDatabaseSchemaUpdate("true");
pe = conf.buildProcessEngine();
}
/**
* 部署流程定义
*/
@Test
public void test1() {
DeploymentBuilder deploymentBuilder = pe.getRepositoryService()
.createDeployment();
deploymentBuilder
.addClasspathResource("com/task/group/groupTask.bpmn");
deploymentBuilder .addClasspathResource("com/task/group/groupTask.png");
Deployment deployment = deploymentBuilder.deploy();
}
/**
* 启动流程实例
*/
@Test
public void test2(){
String processDefinitionId = "grouptTask:1:7404";
pe.getRuntimeService().startProcessInstanceById(processDefinitionId);
}
/**
* 办理个人任务
*/
@Test
public void test3(){
String taskId = "7504";
pe.getTaskService().complete(taskId);
}
/**
* 查询公共任务列表
*/
@Test
public void test4(){
TaskQuery query = pe.getTaskService().createTaskQuery();
String candidateUser = "王五";
//根据候选人过滤
query.taskCandidateUser(candidateUser);
List<Task> list = query.list();
for (Task task : list) {
System.out.println(task.getName());
}
}
/**
* 拾取任务(将公共任务变为个人任务)
*/
@Test
public void test5(){
String taskId = "7602";
String userId = "王五";
pe.getTaskService().claim(taskId , userId);
}
/**
* 退回任务(将个人任务变为公共任务)
*/
@Test
public void test6(){
String taskId = "1602";
pe.getTaskService().setAssignee(taskId , null);
}
}
/**
* RuntimeService得到流程变量
*/
@org.junit.Test
public void testRuntimeServiceGetVar(){
String executionId="5701";
Map<String, Object> variables = processEngine.getRuntimeService().getVariables(executionId);
}
/**
* taskService得到流程变量
*/
@org.junit.Test
public void testTaskServiceGetVar(){
String taskId="5804";
Map<String, Object> variables = processEngine.getTaskService().getVariables(taskId);
}
/**
* 在启动流程实例时设置流程变量
*/
@org.junit.Test
public void testStartProcessInstanceByKey(){
String processDefinitionKey="qjlc";
Map<String,Object> variables = new HashMap<String, Object>();
variables.put("k1", 11);
variables.put("k2", 22);
ProcessInstance query = processEngine.getRuntimeService().startProcessInstanceByKey(processDefinitionKey, variables);
}
/**
* 在办理任务时设置流程变量
*/
@org.junit.Test
public void testTaskComplete(){
String taskId="6002";
Map<String,Object> variables = new HashMap<String, Object>();
variables.put("k3", 11);
variables.put("k4", 22);
processEngine.getTaskService().complete(taskId, variables);
}
/**
* RuntimeService设置流程变量
*/
@org.junit.Test
public void testRuntimeService(){
String executionId="5701";
Map<String,Object> variables = new HashMap<String, Object>();
variables.put("k5", 3);
variables.put("k6", 4);
processEngine.getRuntimeService().setVariables(executionId, variables);
}
/**
* taskService设置流程变量
*/
@org.junit.Test
public void testTaskService(){
String taskId="5804";
Map<String,Object> variables = new HashMap<String, Object>();
variables.put("k5", 31);
variables.put("k6", 41);
processEngine.getTaskService().setVariables(taskId, variables);
}
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class CallAbleTest {
public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService service = Executors.newFixedThreadPool(2);
MyCallAbled m1= new MyCallAbled("aa");
MyCallAbled m2= new MyCallAbled("bb");
Future future1 = service.submit(m1);
Future future2 =service.submit(m2);
System.out.println(future1.get().toString());
System.out.println(future2.get().toString());
service.shutdown();
}
static class MyCallAbled implements Callable{
private String name;
public MyCallAbled(String name){
this.name=name;
}
public MyCallAbled(){
}
@Override
public Object call() throws Exception {
return name;
}
}
}
Java的动态代理是为了拦截目标方法,例子:
public interface Person {
String sing(String name);
String dance(String name);
}
public class Liyuchun implements Person {
public String sing(String name){
System.out.println("唱" + name +"歌");
return "唱" + name +"歌";
}
public String dance(String name){
System.out.println("跳"+name+"舞");
return "跳"+name+"舞";
}
}
public class LiyuchunProxy {
private Person person ;
public Person createProxy(Person p){
this.person=p;
return (Person) Proxy.newProxyInstance(LiyuchunProxy.class.getClassLoader(), person.getClass().getInterfaces(), new InvocationHandler(){
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
String methodName = method.getName();
if(methodName.equals("sing")){
return method.invoke(person, args);
}else if(methodName.equals("dance")){
return method.invoke(person, args);
}else{
System.out.println("不支持");
return null;
}
}
});
}
}
public class ProxyTest {
public static void main(String[] args) {
Liyuchun cun = new Liyuchun();
LiyuchunProxy liyuchunProxy = new LiyuchunProxy();
Person person = liyuchunProxy.createProxy(cun);
String result = person.dance("机械");
System.out.println(result);
}
}
public class Bean1 {
private String a;
private String b;
private String time;
public String getA() {
return a;
}
public void setA(String a) {
this.a = a;
}
public String getB() {
return b;
}
public void setB(String b) {
this.b = b;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
}
public class Bean2 {
private int a;
private String b;
private Date time;
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
public String getB() {
return b;
}
public void setB(String b) {
this.b = b;
}
public Date getTime() {
return time;
}
public void setTime(Date time) {
this.time = time;
}
}
import java.lang.reflect.InvocationTargetException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.Converter;
public class Test {
public static void main(String[] args) throws IllegalAccessException, InvocationTargetException {
Bean1 bean1 = new Bean1();
bean1.setA("22");
bean1.setB("fff");
bean1.setTime("2017-01-22 11:11:11");
Bean2 bean2 = new Bean2();
resp();
BeanUtils.copyProperties(bean2, bean1);
System.out.println(bean2.getA());
System.out.println(bean2.getB());
System.out.println(bean2.getTime());
}
private static void resp() {
ConvertUtils.register(new Converter() {
@Override
public Object convert(Class arg0, Object value) {
if(value != null &&!"".equals(value.toString())){
String v=value.toString();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:MM:ss");
try {
return sdf.parse(v);
} catch (ParseException e) {
e.printStackTrace();
}
}
return null;
}
}, Date.class);
}
}
当一个不在spring容器中的一个类,需要用到事务,这时需要调用spring容器中的其他类来实现事务。比如:
在类中使用context.getBean("aService");得到服务类,此服务类含有事务。
1、配置spring文件:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<!--
读取配置文件
-->
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<value>classpath:jdbc.properties</value>
</property>
</bean>
<bean id="dataSource" destroy-method="close"
class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<bean id="classesDao" class="cn.itheima03.spring.jdbc.ClassesDaoImpl">
<property name="dataSource">
<ref bean="dataSource"/>
</property>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg index="0" ref="dataSource"></constructor-arg>
</bean>
<bean id="classesDao2" class="cn.itheima03.spring.jdbc.ClassesDaoImpl2">
<property name="jdbcTemplate">
<ref bean="jdbcTemplate"/>
</property>
</bean>
<bean id="itheimaTemplate" class="cn.itheima03.spring.itheima03db.ItHeimaTemplate">
<constructor-arg index="0" ref="dataSource"></constructor-arg>
</bean>
<bean id="classesDao4" class="cn.itheima03.spring.itheima03db.ClassesDaoImpl4">
<constructor-arg index="0" ref="dataSource"></constructor-arg>
</bean>
<bean id="classesDao3" class="cn.itheima03.spring.jdbc.ClassesDaoImpl3">
<constructor-arg index="0" ref="dataSource"></constructor-arg>
</bean>
</beans>
2、第一种方式:
public class ClassesDaoImpl extends JdbcDaoSupport implements ClassesDao{
public void saveClasses() {
this.getJdbcTemplate().execute("insert into classes(cname,description) values('a','a')");
}
@Override
public List<Classes> getClasses() {
// TODO Auto-generated method stub
return this.getJdbcTemplate().query("select * from classes", new ClassesRowMapper());
}
}
3、第二种方式:
public class ClassesDaoImpl2 implements ClassesDao{
private JdbcTemplate jdbcTemplate;
public JdbcTemplate getJdbcTemplate() {
return jdbcTemplate;
}
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public void saveClasses() {
// TODO Auto-generated method stub
this.jdbcTemplate.execute("insert into classes(cname,description) values('a','a')");
}
@Override
public List<Classes> getClasses() {
// TODO Auto-generated method stub
return null;
}
}
4.第三种方式:
public class ClassesDaoImpl3 extends JdbcTemplate implements ClassesDao{
public ClassesDaoImpl3(DataSource dataSource){
super(dataSource);
}
public void saveClasses() {
this.execute("insert into classes(cname,description) values('a','a')");
}
@Override
public List<Classes> getClasses() {
return null;
}
}
5、自定义数据库操作类:
public class ItHeimaTemplate {
private DataSource dataSource;
public DataSource getDataSource() {
return dataSource;
}
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
public ItHeimaTemplate(){}
public ItHeimaTemplate(DataSource dataSource){
this.dataSource = dataSource;
}
public void insert(String sql){
try {
Connection conn = this.dataSource.getConnection();
Statement statement = conn.createStatement();
statement.executeUpdate(sql);
} catch (Exception e) {
}
}
}
public class ClassesDaoImpl4 extends ItHeimaTemplate{
public ClassesDaoImpl4(DataSource dataSource){
super(dataSource);
}
public void insert(){
this.insert("insert into classes(cname,description) values('a','a')");
}
}
$().ready(function(){
for (var i = 0; i < 300; i++) {
$("input[type='button']").unbind("click");
$("input[type='button']").bind("click",function(){
/**
* 触发自定义的事件
*/
$(this).trigger("杨军威",{
a:5,
b:6
});
});
}
$("input[type='button']").unbind("杨军威");
$("input[type='button']").bind("杨军威",function(event,json){
alert(json.a+json.b);
});
});
/**
* 自定义事件
* 1、自定义一个事件,该事件的名称为"云三很牛"
* 2、把该事件绑定在button上
* 3、该事件在点击button的时候触发
*/
1、session有缓存功能,但是当session关闭后,缓存消失。
2.二级缓存是sessionfactory级别的,当hibernate容器启动后,
二级缓存就存在了,当hibernate关闭后,二级缓存消失。
hibernate本身对于二级缓存是关闭的,而且没有实现二级缓存的机制。
在hibernate.cfg.xml文件中配置:
<!-- 启用二级缓存 --><property name="hibernate.cache.use_second_level_cache">true</property><property name="hibernate.cache.use_query_cache">true</property><!-- 配置缓存提供商 --><property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
在实体类中配置
<class-cache class="com.nacosoft.pda.user.PdaUser" usage="read-write" />
如果想开启集合的二级缓存,需要开启针对集合类的二级缓存。
如果二级缓存的数据量大,可以在src目录下新建ehcache.xml文件,把数据缓存在磁盘上。
3.查询缓存:在二级缓存的基础上,在代码里写:
Query query = session.createQuery("from Person");
query.setCacheable(true);
List list = query.list();
就可以使用查询缓存了
1、sessionFactory.openSession(),只要调用此方法,就会产生一个新的session。
2、sessionFactory.getCurrentSession()产生session的逻辑是:
先判断当前线程中有无session,如果没有,调用sessionFactory.openSession()产生新的session,
并放入到当前线程中。如果session存在,直接取当前线程中的session,当使用此方法产生的session时,
crud操作必须在事务中进行,并且不用关闭session。
jdbc的缺点:
1.代码太繁琐,2、不是面向对象的数据库操作。
3、资源关闭的代码繁琐,每次都需要打开和关闭。
4、没有数据缓存。5、数据库移植性差。
优点:是最底层的操作,所以效率高。
hibernate优点:
1、代码精简、2、是面向对象的数据库操作
3.只需要关闭一个session对象就可以了
4.数据有缓存,一级缓存和二级缓存用于查询缓存
5.都是面向对象操作,数据库移植性好。
缺点:1、程序无法控制sql的生成,如果系统重视对sql优化,不适合用hibernate。
2、如果单表数据量超过一千万,不适合用hibernate
前端传递json数据,配置第一种方法
<!-- media type -->
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-moxy</artifactId>
<version>${jersey.version}</version>
</dependency>
@ApplicationPath("/webapi/*")
public class AirResourceConfig extends ResourceConfig {
public AirResourceConfig() {
// packages("com.example.resource");
register(BookResource.class);
}
}
前端传递json数据,配置第二种方法
<!-- media type -->
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>${jersey.version}</version>
</dependency>
@ApplicationPath("/api/*")
public class JsonResourceConfig extends ResourceConfig {
public JsonResourceConfig() {
register(BookResource.class);
register(JacksonFeature.class);
register(JsonContextProvider.class);
}
}
@Provider
public class JsonContextProvider implements ContextResolver<ObjectMapper> {
final ObjectMapper d;
final ObjectMapper c;
public JsonContextProvider() {
d = createDefaultMapper();
c = createCombinedMapper();
}
private static ObjectMapper createCombinedMapper() {
Pair ps = createIntrospector();
ObjectMapper result = new ObjectMapper();
//result.configure(Feature.WRAP_ROOT_VALUE, true);
//result.configure(DeserializationConfig.Feature.UNWRAP_ROOT_VALUE, true);
result.setDeserializationConfig(result.getDeserializationConfig().withAnnotationIntrospector(ps));
result.setSerializationConfig(result.getSerializationConfig().withAnnotationIntrospector(ps));
return result;
}
private static ObjectMapper createDefaultMapper() {
ObjectMapper result = new ObjectMapper();
result.configure(Feature.INDENT_OUTPUT, true);
return result;
}
private static Pair createIntrospector() {
AnnotationIntrospector p = new JacksonAnnotationIntrospector();
AnnotationIntrospector s = new JaxbAnnotationIntrospector();
return new Pair(p, s);
}
@Override
public ObjectMapper getContext(Class<?> type) {
if (type == JsonHybridBook.class) {
return c;
} else {
return d;
}
}
}
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Test {
private static Iterator<String> iterator;
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("1");
list.add("2");
iterator = list.iterator();
while (iterator.hasNext()) {
String next = iterator.next();
if("1".equals(next)){
list.remove(next);
}
}
for(String s : list){
System.out.println(s);
}
}
}
jersey容器发布web应用不需要web.xml的开发。
1.新建容器扫描类
package com.example;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import org.glassfish.jersey.servlet.ServletContainer;
@WebServlet(
initParams = @WebInitParam(name = "jersey.config.server.provider.packages", value = "com.example"),
urlPatterns = "/webapi/*",
loadOnStartup = 1)
public class AirServlet extends ServletContainer {
private static final long serialVersionUID = 1L;
}
在com.example包中的资源服务类都可以访问到
jersey不用添加扫描包,自动扫描资源服务类。
在web.xml文件中添加
<servlet>
<servlet-name>javax.ws.rs.core.Application</servlet-name>
</servlet>
<servlet-mapping>
<servlet-name>javax.ws.rs.core.Application</servlet-name>
<url-pattern>/webapi/*</url-pattern>
</servlet-mapping>
这样可以自动扫描所有的资源服务类
在使用jersey中,web.xml文件也可以不用。
1、新建jersey容器类
package com.example;
import javax.ws.rs.ApplicationPath;
import org.glassfish.jersey.server.ResourceConfig;
@ApplicationPath("/webapi/*")
public class AirResourceConfig extends ResourceConfig {
public AirResourceConfig() {
packages("com.example");
}
}
或者
package com.example;
import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
@ApplicationPath("/webapi/*")
public class AirApplication extends Application {
@Override
public Set<Class<?>> getClasses() {
final Set<Class<?>> classes = new HashSet<Class<?>>();
classes.add(MyResource.class);
return classes;
}
}
把所有的资源服务类加入到set中
@ApplicationPath定义了访问的地址,packages("com.example");定义了扫描的资源服务类的包
1、先在pom.xml文件中添加依赖:
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet-core</artifactId>
</dependency>
</dependencies>
2、在web.xml中添加jersey类
<servlet>
<servlet-name>Jersey Web Application</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.example.AirApplication</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey Web Application</servlet-name>
<url-pattern>/webapi/*</url-pattern>
</servlet-mapping>
其中com.example.AirApplication类扫描所有的对外服务类
3、新建对外服务类
package com.example;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
/**
* Root resource (exposed at "myresource" path)
*/
@Path("myresource1")
public class MyResource1 {
@GET
@Produces(MediaType.TEXT_PLAIN)
public String getIt() {
return "Got it222!";
}
}
package com.example;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
/**
* Root resource (exposed at "myresource1" path)
*/
@Path("myresource1")
public class MyResource1 {
@GET
@Produces(MediaType.TEXT_PLAIN)
public String getIt() {
return "Got it222!";
}
}
4、在AirApplication类中扫描服务类
package com.example;
import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.core.Application;
public class AirApplication extends Application {
@Override
public Set<Class<?>> getClasses() {
final Set<Class<?>> classes = new HashSet<Class<?>>();
classes.add(MyResource.class);
classes.add(MyResource1.class);
return classes;
}
}
这样在tomcat中启动就可以访问资源类中的方法。
1.新建一个实体类
package com.example.domain;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "device")
public class Device {
private String deviceIp;
private int deviceStatus;
public Device() {
}
public Device(String deviceIp) {
super();
this.deviceIp = deviceIp;
}
@XmlAttribute
public String getIp() {
return deviceIp;
}
public void setIp(String deviceIp) {
this.deviceIp = deviceIp;
}
@XmlAttribute
public int getStatus() {
return deviceStatus;
}
public void setStatus(int deviceStatus) {
this.deviceStatus = deviceStatus;
}
}
其中@XmlRootElement(name = "device")代表xml文件的根节点
@XmlAttribute代表xml文件的属性节点
在pom.xml文件中依赖下面2包
<dependencies>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-grizzly2-http</artifactId>
</dependency>
<!-- get JSON support: -->
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-moxy</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.9</version>
<scope>test</scope>
</dependency>
</dependencies>
在服务类中编写
package com.example;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import com.example.domain.Device;
@Path("myresource")
public class MyResource {
@GET
@Produces({ MediaType.APPLICATION_JSON })
public Device getIt() {
Device d=new Device("1.1.1.1");
d.setStatus(2);
return d;
}
}
建立测试类:
package com.example;
import java.io.IOException;
import java.net.URI;
import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
import org.glassfish.jersey.server.ResourceConfig;
public class Main {
public static final String BASE_URI = "http://localhost:8080/myapp/";
public static HttpServer startServer() {
final ResourceConfig rc = new ResourceConfig().packages("com.example");
return GrizzlyHttpServerFactory.createHttpServer(URI.create(Main.BASE_URI), rc);
}
public static void main(String[] args) throws IOException {
final HttpServer server = Main.startServer();
}
}
启动后在浏览器中输入http://localhost:8080/myapp/myresource,页面返回
{"ip":"1.1.1.1","status":2}
返回json格式的数据。
根据流程定义中的pdkey-->查询出所有的流程定义--》根据流程定义中的DeploymentId删除流程部署
String url="http://localhost:8984/axis/HelloWs.jws";//服务地址
Service s = new Service();
Call call = s.createCall();
call.setTargetEndpointAddress(url);
call.setOperationName(new QName(url, "getH"));//调用的服务端方法名称
Object invoke = call.invoke(new Object[]{"a"});//传递的参数
System.out.println(invoke);
1、创建自己的handler类实现SOAPHandler接口,实现里面的方法。
2、新增handler-chain.xml文件,
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<javaee:handler-chains
xmlns:javaee="http://java.sun.com/xml/ns/javaee"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<javaee:handler-chain>
<javaee:handler>
<javaee:handler-class>com.ws.MsgHandler</javaee:handler-class>
</javaee:handler>
</javaee:handler-chain>
</javaee:handler-chains>
3、在webservice实现类中添加文件的地址 @HandlerChain(file="handler-chain.xml")
4、
wsimport -d [目录] -keep -verbose [wsdl地址]
session是在服务端开辟的一块内存,有唯一的sessionid,如果客户端没有禁用cookie,sessionid就保存在客户端的cookie中;如果客户端禁用了cookie,客户端的url后面就跟上;jsessionid=111。来想服务器传递sessionid,可以保证sessionid不变。
/**
* Created by Administrator on 2017/3/24.
*/
var extend=function (c,f) {
c.prototype=f.prototype;
}
var f=function () {
this.a='aa';
}
f.prototype={
say:function () {
alert('f');
}
}
var c=function () {
this.b='aa';
}
extend(c,f);//只能继承prototype实现的方法
var c1=new c();
c1.say();
Ext.namespace('com.ext');
com.ext.First=function () {
var kiss='中国';
}
com.ext.First.prototype={
init:function () {
alert('init');
alert('kiss');
},
method:function () {
alert('method');
}
}
//var f=new com.ext.First();
//f.method();
com.ext.Second=function () {
}
Ext.extend(com.ext.Second,com.ext.First,{
method:function () {
alert('method2');
},
fun:function () {
alert('fun');
}
});
var s=new com.ext.Second();
s.method();
s.fun();
Student=function (config) {
this.a='3';
Ext.apply(this,config);
}
var st=new Student({a:'1',b:'2'});
alert(st.a);
Student1=function (config) {
this.a='3';
Ext.applyIf(this,config);
}
var st=new Student1({a:'1',b:'2'});
alert(st.a);
/**apply方法覆盖所有的属性
* applyIf不覆盖属性
*
*/
1.准备jar包将ik的jar包、pinyin4j-2.5.0.jar、solr-4.9.0\contrib\analysis-extras\lucene-libs\lucene-analyzers-smartcn-4.9.0.jar拷贝到%TOMCAT_HOME%\webapps\solr\WEB-INF\lib下
2.修改schema.xml<fieldType name="text_pinyin" class="solr.TextField" positionIncrementGap="0">
<analyzer type="index">
<tokenizer class="org.apache.lucene.analysis.cn.smart.SmartChineseSentenceTokenizerFactory"/>
<filter class="org.apache.lucene.analysis.cn.smart.SmartChineseWordTokenFilterFactory"/>
</analyzer>
<analyzer type="query">
<tokenizer class="org.apache.lucene.analysis.cn.smart.SmartChineseSentenceTokenizerFactory"/>
<filter class="org.apache.lucene.analysis.cn.smart.SmartChineseWordTokenFilterFactory"/>
</analyzer>
</fieldType>
<fieldType name="text_smartcn" class="solr.TextField" positionIncrementGap="0">
<analyzer type="index">
<tokenizer class="org.apache.lucene.analysis.cn.smart.SmartChineseSentenceTokenizerFactory"/>
<filter class="org.apache.lucene.analysis.cn.smart.SmartChineseWordTokenFilterFactory"/>
</analyzer>
<analyzer type="query">
<tokenizer class="org.apache.lucene.analysis.cn.smart.SmartChineseSentenceTokenizerFactory"/>
<filter class="org.apache.lucene.analysis.cn.smart.SmartChineseWordTokenFilterFactory"/>
</analyzer>
</fieldType>
3.需要拼音分词的字段使用这些fieldType
4.在搜索字段时配上这些拼音字段
参与权重的查询字段最好是可以进行分词配置过的,
例子程序:
//权重
query.set("defType","dismax");
query.set("qf","username^10000 zgxltext^10000 usernameSpell^10000 id^10000 email^10000 jgtext^10000 xueweitext^10000 zhiweitext^10000 sextext^10000 zhijitext^10000 companytext^10000 zuzhitext^10000 companysubtext^10000 sbfamily^1 sbharvest^1 sbproject^1 sbteach^1 sbwaiyu^1 sbwork^1 sbzhiCheng^1 ");
//高亮
query.setHighlight(true);
query.setParam("hl", "true"); //highlighting
query.setParam("hl.fl", "username id email jgtext xueweitext zhiweitext sextext zhijitext companytext zuzhitext companysubtext zgxltext");
query.setHighlightSimplePre("<font color=\'red\'>");
query.setHighlightSimplePost("</font>");
query.setHighlightFragsize(200);
query.setHighlightSnippets(3);
List<SPEntity> lpojo = response.getBeans(SPEntity.class);
Map<String, Map<String, List<String>>> highlighting = response.getHighlighting();
List<String> list2 =null;
//
if (lpojo != null && lpojo.size()>0 && highlighting != null){
for(SPEntity sp : lpojo){
Map<String, List<String>> map = highlighting.get(sp.getId());
list2 = map.get("username");
if (list2 != null && list2.size()>0){
sp.setUsername(list2.get(0));
}
list2 = map.get("id");
if (list2 != null && list2.size()>0){
sp.setId(list2.get(0));
}
list2 = map.get("email");
if (list2 != null && list2.size()>0){
sp.setEmail(list2.get(0));
}
list2 = map.get("jgtext");
if (list2 != null && list2.size()>0){
sp.setJgtext(list2.get(0));
}
list2 = map.get("xueweitext");
if (list2 != null && list2.size()>0){
sp.setXueweitext(list2.get(0));
}
list2 = map.get("zhiweitext");
if (list2 != null && list2.size()>0){
sp.setZhiweitext(list2.get(0));
}
list2 = map.get("sextext");
if (list2 != null && list2.size()>0){
sp.setSextext(list2.get(0));
}
list2 = map.get("zhijitext");
if (list2 != null && list2.size()>0){
sp.setZhijitext(list2.get(0));
}
list2 = map.get("companytext");
if (list2 != null && list2.size()>0){
sp.setCompanytext(list2.get(0));
}
list2 = map.get("zuzhitext");
if (list2 != null && list2.size()>0){
sp.setZuzhitext(list2.get(0));
}
list2 = map.get("companysubtext");
if (list2 != null && list2.size()>0){
sp.setCompanysubtext(list2.get(0));
}
list2 = map.get("zgxltext");//
if (list2 != null && list2.size()>0){
sp.setZgxltext(list2.get(0));
}
}
}
客户端系统js代码:
<script type="text/javascript">
function test(a){
alert(a.name);
return a;
}
$.ajax({
url:'http://ip:8090/mobile/test.json?method=test',
type:'POST', //GET
async:true, //或false,是否异步
data:{
// name:'yang',age:25
},
timeout:5000, //超时时间
dataType:'jsonp', //返回的数据格式:json/xml/html/script/jsonp/text
beforeSend:function(xhr){
},
success:function(data,textStatus,jqXHR){
},
error:function(xhr,textStatus){
},
complete:function(){
}
})
</script>
服务端系统代码:
test({name:'yang',age:25});
客户端访问跨域系统时,传递客户端需要执行的方法名,服务端在查询出数据后,使用传递的方法名封装成js方法的执行返回,客户端程序就直接执行此方法。
springmvc后台例子,返回jsonp数据代码
//第一种字符串返回jsonp格式数据
@RequestMapping(value="/get/{method}",produces=MediaType.APPLICATION_JSON_VALUE+";charset=utf-8")
@ResponseBody
public String getUser(@PathVariable String method) {
User user = userService.selectByPrimaryKey(1);
Gson gson = new Gson();
String userJson = gson.toJson(user);
return method+"("+userJson+")";
}
//第二种对象返回jsonp格式数据
spring版本4.1以上
@RequestMapping("/gett/{method}")
@ResponseBody
public Object gett(@PathVariable String method) {
User user = userService.selectByPrimaryKey(1);
MappingJacksonValue mjv = new MappingJacksonValue(user);
mjv.setJsonpFunction(method);
return mjv;
}
spring容器是父容器,包含的对象有dao,service等
springmvc容器是子容器,包括controller
子容器可以访问父容器的 对象,但是子容器不可以访问父容器的属性。
父容器不能访问子容器的对象。
例如,controller可以访问service,但是service不能访问controller。
upstream project
{
server 127.0.0.1:8080 weight=3; tomcat地址
server 127.0.0.1:8082; tomcat地址
}
server {
listen 80; 发布的访问地址的端口
server_name test.tt.com; 发布的访问地址
location / {
proxy_pass http://project;
index index.html index.htm;
}
}
1、mvn compile 编译源代码
2、mvn test 执行所有的测试类方法
3、mvn clean 清除class
4、mvn package 打包
5、mvn install 安装到本地仓库中
6、 mvn archetype:generate -DgroupId=com.aaa.bbb -DartifactId=ccc-bbb -Dversion=0.0.1-SNAPSHOT 新建项目
7、<dependency>
<groupId></groupId>
<artifactId></artifactId>
<version></version>
<scope>compile</scope>编译和打包的时候会依赖(这个属性是默认的)
<scope>provided</scope>编译和测试的时候依赖,打包的时候不依赖,例如servlet-api,打包的时候tomcat中有,会冲突,所有不打包,但是编译和测试的时候需要这个jar。
<scope>test</scope> 在测试范围有效,在编译和打包的时候不会使用这个依赖。并且不会传递依赖,例如,其他项目依赖此包时,此jar不会被传递依赖。
<scope>runtime</scope> 在运行的时候依赖,在编译的时候不依赖。
</dependency>
8、a-->直接依赖jar1.1 , b-->直接依赖jar1.2 , c-->直接依赖a,b ,c先依赖a,后依赖b,所以a依赖jar1.1版本
9、当依赖级别相同的时候,先依赖谁,就用它,当依赖级别不同的时候,用依赖级别短的依赖。
10、<exclusions>
<exclusion>
</exclusion>
</exclusions>
的意思是说不使用此jar依赖的某个jar包,可以解决jar冲突的问题。
11、继承的绝对路径是pom文件,聚合的是模块的位置。
1.下载oracle jar包,放在计算机用户目录下,例如C:\Users\Administrator目录下。
2.在cmd下执行
mvn install:install-file -DgroupId=com.Oracle -DartifactId=ojdbc14 -Dversion=10.2.0.2.0 -Dpackaging=jar -Dfile=ojdbc14.jar -DgeneratePom=true
这样加把jar加载到本地库了。
/**
* 通过数据库类型处理翻页查询语句
* 注释:如果框架当前不支持此种数据库分页查询,则返回一个空值字符串。
* * @param strSql 待执行SQL语句
* @param start 开始行数
* @param pageCount 每页行数
* */
private static String dealSqlByDBType(String dbType,String strSql,int start,int pageCount)
{
if(dbType==null)return "";
String retSql = "";
if(dbType.equals("mysql"))
{
//MYSQL数据库采用limit关键字进行分页
int startItem = start -1;if(startItem<0)startItem = 0;
retSql = strSql + " limit " + startItem + "," + pageCount;
}
else if(dbType.equals("oracle"))
{
//ORACLE数据库采用ROWNUM控制分页
int startItem = start;
if(startItem<=0){startItem = 0;}
int endItem = startItem + pageCount;
retSql = "SELECT * FROM ("
+ "SELECT A.*,ROWNUM RN FROM("
+ strSql
+ ") A WHERE ROWNUM<="+ endItem +") WHERE RN >"+startItem;
}
else if(dbType.equals("db2"))
{
//DB2数据库采用ROWNUMBER() OVER()函数进行分页
//其中OVER()函数中必须包含排序字段,此处用“1”代替
int startItem = start -1;if(startItem<0)startItem = 0;
int endItem = startItem + pageCount;
retSql = "SELECT * FROM ("
+ "SELECT B.*, ROWNUMBER() OVER(1) AS RN FROM ("
+ strSql
+ ") AS B )AS A WHERE A.RN <= "+ endItem +" AND A.RN >= "+ startItem;
}
else if(dbType.equals("sqlserver2005"))
{
//SQLSERVER2005采用ROW_NUMBER()函数进行分页
//其中OVER()函数中必须包含排序字段,此处用“1”代替
int startItem = start -1;if(startItem<0)startItem = 0;
int endItem = startItem + pageCount;
retSql = "SELECT * FROM ("
+ "SELECT B.*, ROW_NUMBER() OVER(1) RN FROM ("
+ strSql
+ ") B )A WHERE A.RN <= "+ endItem +" AND A.RN >= "+ startItem;
}
else if(dbType.equals("derby"))
{
//通过OFFSET等关键字进行翻页(尚未经过测试)
int startItem = start -1;if(startItem<0)startItem = 0;
//int endItem = startItem + pageCount;
retSql = strSql
+ " OFFSET "+ startItem +" ROWS"
+ " FETCH NEXT "+ pageCount +" ROWS ONLY";
}
return retSql;
}
String objParam = "{name:\"c\",configType:1,list:[{label:\"c\",tableName:\"c\",vfiled:\"c\",category:\"c\"},{label:\"c\",tableName:\"c\",vfiled:\"c\",category:\"c\"}]}";//request.getParameter("objParam");
JSONObject jsonObject = JSONObject.fromObject(objParam);
Map
classMap = new HashMap();
classMap.put("list", DtoSearch.class);
ResultData resultData = (ResultData) net.sf.json.JSONObject.toBean(
jsonObject, ResultData.class, classMap);
在window上安装solr步骤
1.在tomcat的目录中放入solr的索引库
2.在webapps中放入solr的应用程序
3.在tomcat_file/solr/目录中新建collection1目录, 放入搜索库文件,新建data文件夹,存放索引文件。
新建core.properties文件,写name=collection1。在/app/tomcat_file/solr/collection1/conf目录中,
修改scripts.conf文件。写上 <dataDir>${solr.data.dir:D:/app/tomcat_file/solr/collection1/data}</dataDir>。
5,在/app/tomcat_file/webapps/solr/WEB-INF中的web.xml文件中,配置:
<env-entry>
<env-entry-name>solr/home</env-entry-name>
<env-entry-value>D:/tomcat_file/solr</env-entry-value>
<env-entry-type>java.lang.String</env-entry-type>
</env-entry>
6.启动tomcat,配置solr成功
在Linux上安装solr步骤
1.在tomcat的目录中放入solr的索引库
2.在webapps中放入solr的应用程序
3.在/app/tomcat_file/conf/Catalina/localhost中新建solr.xml文件,内容是:
<?xml version="1.0" encoding="UTF-8"?>
<Context docBase="/app/tomcat_file/webapps/solr" debug="0" crossContext="true" >
<Environment name="solr/home" type="java.lang.String" value="/app/tomcat_file/solr" override="true" />
</Context>
4.在/app/tomcat_file/solr/目录中新建collection1目录, 放入搜索库文件,新建data文件夹,存放索引文件。
新建core.properties文件,写name=collection1。在/app/tomcat_file/solr/collection1/conf目录中,
修改scripts.conf文件。写上 <dataDir>${solr.data.dir:/app/tomcat_file/solr/collection1/data}</dataDir>。
5,在/app/tomcat_file/webapps/solr/WEB-INF中的web.xml文件中,配置:
<env-entry>
<env-entry-name>solr/home</env-entry-name>
<env-entry-value>/app/tomcat_file/solr</env-entry-value>
<env-entry-type>java.lang.String</env-entry-type>
</env-entry>
6.启动tomcat,配置solr成功
1.
@ExceptionHandler(ArithmeticException.class)
public ModelAndView getArithmeticException(Exception ex){
ModelAndView mv = new ModelAndView("error");
mv.addObject("ex", ex);
return mv;
}
@RequestMapping("/zero")
public void ac(@RequestParam("i") int i){
System.out.println(10/i);
}
当发生ArithmeticException异常的时候,在error.jsp页面输出异常 。
2.
@ControllerAdvice
public class Exceptions {
@ExceptionHandler(ArithmeticException.class)
public ModelAndView getArithmeticException(Exception ex){
ModelAndView mv = new ModelAndView("error");
mv.addObject("ex", ex);
return mv;
}
}
如果在本类中找不到异常处理的方法,就去@ControllerAdvice注解的类中查找异常处理的类的方法。
3.
@ResponseStatus(value=HttpStatus.BAD_REQUEST,reason="请求不对")
public class UserExceptions extends RuntimeException{
/**
*
*/
private static final long serialVersionUID = 1L;
}
在controller的方法里抛出UserExceptions 异常,在页面上显示
HTTP Status 400 - 请求不对
java不同版本加载jar的顺序不一样,window和Linux中,java不同版本加载jar的顺序不一样,所有不要以为在一个java版本和一个操作系统上成功运行成功,就认为程序没问题。只有在不同java版本和不同操作系统上都运行成功,才说明程序没问题。在java8一样的情况下,window和Linux加载spring的jar文件顺序不一样!!!!!!
一、在oracle11G以前卸载oracle会存在卸载不干净,导致再次安装失败的情况,在运行services.msc打开服务,停止Oracle的所有服务。
二、 oracle11G自带一个卸载批处理\app\Administrator\product\11.2.0\dbhome_1\deinstall\deinstall.bat运行该批处理程序将自动完成oracle卸载工作,最后手动删除\app文件夹(可能需要重启才能删除)
运行过程中可能需要填写如下项:
- 指定要取消配置的所有单实例监听程序[LISTENER]:LISTENER
- 指定在此 Oracle 主目录中配置的数据库名的列表 [MYDATA,ORCL]: MYDATA,ORCL
- 是否仍要修改 MYDATA,ORCL 数据库的详细资料? [n]: n
- CCR check is finished
- 是否继续 (y - 是, n - 否)? [n]: y
三、运行regedit命令,打开注册表。删除注册表中与Oracle相关内容,具体下:
- 删除HKEY_LOCAL_MACHINE/SOFTWARE/ORACLE目录。
- 删除HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services中所有以oracle或OraWeb为开头的键。
- 删除HKEY_LOCAL_MACHINE/SYSETM/CurrentControlSet/Services/Eventlog/application中所有以oracle开头的键。
- 删除HKEY_CLASSES_ROOT目录下所有以Ora、Oracle、Orcl或EnumOra为前缀的键。
- 删除HKEY_CURRENT_USER/SOFTWARE/Microsoft/windows/CurrentVersion/Explorer/MenuOrder/Start Menu/Programs中所有以oracle 开头的键。
- 删除HKDY_LOCAL_MACHINE/SOFTWARE/ODBC/ODBCINST.INI中除Microsoft ODBC for Oracle注册表键以外的所有含有Oracle的键。
- 删除环境变量中的PATHT CLASSPATH中包含Oracle的值。
- 删除“开始”/“程序”中所有Oracle的组和图标。
- 删除所有与Oracle相关的目录,包括: (1)、c:\Program file\Oracle目录。 (2)、ORACLE_BASE目录。(3)、c:\Documents and Settings\系统用户名、LocalSettings\Temp目录下的临时文件。
(function (){
function Person(){
this.getAge=function (age){
alert(age);
}
}
//让此类的所有对象有name属性,showName方法
Person.prototype.name="yjw";
Person.prototype.showName=function(){
alert(this.name);
}
// new Person().showName();
var v={};
//让空对象v继承Person,含有Person的所有属性和方法
v.__proto__=new Person();
v.__proto__.constructor=v;
v.getAge(1);
v.showName();
})()
(function (){
//创建一个人员类
function Person(n){
this.name=n;
this.getAge=function (age){
alert(age);
}
}
//创建教师类
function Teacher(name,books){
//call方法可以将一个函数的对象上下文,从初始化变成由this来决定
//调用Person的构造函数,
Person.call(this, name);//this就是person的this,name属性就是person的属性
this.books=books;
}
//让教师类继承人员类
Teacher.prototype=new Person();
Teacher.prototype.constructor=Teacher;//教师的构造方法还是使用教师自己的构造方法
Teacher.prototype.getBook = function(){//给教师类的原型添加方法
return this.name+" "+this.books;
}
var jim = new Teacher("jim","extjs");
// alert(jim.getBook());
//jim.getAge(2);
function extend(subClass,superClass){
//1.让子类原型类属性等于父类的原型属性,初始化一个中间空对象,为了转换主父类关系
var f = function(){};
f.prototype=superClass.prototype;
//2.让子类继承f
subClass.prototype=new f();
subClass.prototype.constructor=subClass;
//3.为子类增加属性,继承父类的原型对象
subClass.fuLei=superClass.prototype;
//4.增加一个保险,就算父类的原型类是超类object,也要把父类的构造函数的级别降下来
if(superClass.prototype.constructor==Object.prototype.constructor){
superClass.prototype.constructor=superClass;
}
}
function Student(name,books){
Student.fuLei.constructor.call(this,name);
this.books=books;
this.getBooks=function(){
return this.name+" "+this.books;
}
}
extend(Student, Person);
var s = new Student("s","a");
alert(s.getBooks());
s.getAge(2);
})()
1.如果两个网站域名的一级域名相同,可以使用cookie和filter实现单点登录,因为网站有可能(具体看cookie的设置)可以共享cookie。例如:www.bbs.aa.cn www.news.aa.cn。
第一个网站在登录后,把用户信息写到cookie中,当访问第二个网站时,第二个网站先经过自己的filter,检查session,如果没有,查询cookie,取出用户信息,放在session中登录。
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
if(request.getSession().getAttribute("user")== null){
Cookie[] cs = request.getCookies();
if (cs != null && cs.length > 0) {
for (Cookie c : cs) {
String cName = c.getName();
if (cName.equals("sso")) {
String userName = c.getValue();
request.getSession().setAttribute("user", userName);
}
}
}
}
chain.doFilter(request, resp);
}
2.如果两个网站域名的一级域名不同,不可以使用cookie和filter实现单点登录,因为网站不可以共享cookie。例如:www.bbs.cn www.news.cn。
使用cas框架服务实现单点登录。1.部署cas服务端。2.在服务器端的ticketGrantingTicketCookieGenerator.xml中修改文件。<bean id="ticketGrantingTicketCookieGenerator" class="org.jasig.cas.web.support.CookieRetrievingCookieGenerator"
p:cookieSecure="false"//使用http协议
p:cookieMaxAge="-1"//cookie有效时间
p:cookieName="yjwname"//cookie名称
p:cookiePath="/" />//项目名称
3.部署www.bbs.cn www.news.cn服务,在每个客户端项目中加入casjar包,在web.xml中配置<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (c) 2008, Martin W. Kirst
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the Martin W. Kirst nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-->
<web-app id="mywebapp" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>mywebapp</display-name>
<description>
Simple sample, how to use CAS Java Client 3.x.
In this sample exists a public area (/)
and a private area (/protected/*).
</description>
<!-- Sign out not yet implemented -->
<!--
<filter>
<filter-name>CAS Single Sign Out Filter</filter-name>
<filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>
</filter>
-->
<filter>
<filter-name>CAS Authentication Filter</filter-name>
<filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
<init-param>
<!--cas服务器地址-->
<param-name>casServerLoginUrl</param-name>
<param-value>http://www.service.com:8081/login</param-value>
</init-param>
<init-param>
<!--自己的地址-->
<param-name>serverName</param-name>
<param-value>http://www.bbs.com:8081</param-value>
</init-param>
<init-param>
<param-name>renew</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>gateway</param-name>
<param-value>false</param-value>
</init-param>
</filter>
<filter>
<filter-name>CAS Validation Filter</filter-name>
<filter-class>org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter</filter-class>
<init-param>
<param-name>casServerUrlPrefix</param-name>
<param-value>http://www.service.com:8081</param-value>
</init-param>
<init-param>
<param-name>serverName</param-name>
<param-value>http://www.bbs.com:8081</param-value>
</init-param>
</filter>
<filter>
<filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
<filter-class>org.jasig.cas.client.util.HttpServletRequestWrapperFilter</filter-class>
</filter>
<filter>
<filter-name>CAS Assertion Thread Local Filter</filter-name>
<filter-class>org.jasig.cas.client.util.AssertionThreadLocalFilter</filter-class>
</filter>
<!-- ************************* -->
<!-- Sign out not yet implemented -->
<!--
<filter-mapping>
<filter-name>CAS Single Sign Out Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
-->
<filter-mapping>
<filter-name>CAS Authentication Filter</filter-name>
<!--此URL下的资源都需要验证登录-->
<url-pattern>/protected/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>CAS Validation Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>CAS Assertion Thread Local Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>CAS Validation Filter</filter-name>
<url-pattern>/proxyCallback</url-pattern>
</filter-mapping>
<!-- *********************** -->
<!-- Sign out not yet implemented -->
<!--
<listener>
<listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
</listener>
-->
</web-app>
4.启动服务,这样就可以实现单点登录
在web.xml中配置
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value><!-- 强制进行转码 -->
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
<div id="mydiv">aaaaa</div>
<div id="mydiv1" onclick="test();">bbbbb</div>
<div id="mydiv2" onclick="test2(this);">bbbbb</div>
</body>
<script type="text/javascript" >
document.getElementById('mydiv').onclick=test1;
//相当于 对象.属性=test1,相当于对象拥有了test1属性,this指向当前对象
function test1(){
this.style.color='red';
}
function test(){
this.style.color='red';
}
function test2(t){
t.style.color='red';
}
//1.我们在js定义的所有的全局变量 和方法,都是需要附属在window上的,当成window的属性,所以在test方法中的
//this指向window,不是当前元素,所以test方法执行报错。在js中,规定,函数被哪个元素调用,this指向这个元素。
//当方法被动态绑定时,是当前元素调用方法,当行内绑定时,如果不在方法中传入当前对象,方法中的this指向window。
</script>
</html>
1.查看文件命令
命令格式:ls -la (查看所有文件,包括隐藏文件)
ls -l 或者ll (显示文件详细信息)
ls -d (查看目录属性)
2.文件类型和权限标示
- rw- rw- r--
-表示文件 d表示目录 l表示软链接文件
rw- 表示所有者的权限
rw-表示所有组的权限
r--表示其他人的权限
r读权限w写权限x执行权限
3.命令mkdir 创建目录 mkdir -p 递归创建目录
4.cd 进入目录 cd .. 返回上层目录
5.pwd 显示当前所在目录
6.rmdir 删除空目录
7.cp -r 复制目录 目的目录 cp -p 复制目录 目的目录,保留文件属性
8.mv 剪切文件或者目录或者 修改文件名
9.rm -r 删除目录 rm -f 强制执行 rm -rf 强制删除文件或者目录
10.touch 创建文件
11. cat 查看文件全文 cat -n 显示行号
12.more 查看大文件,f或者空格 向下翻页,enter 向下每行显示,
13.less 向上翻页查看大文件
14.head 文件名 head -n 10查看文件头10行
15.tail -n 10 文件名 ,查看文件尾部10行
16.tail -f 文件夹 实时查看文件变化
设置时间伟2008年8月8号12:00# date -s "2008-08-08 12:00:00"修改完后,记得执行clock -w,把系统时间写入CMOS
<script type="text/javascript" >
(function(){
i=10;
function aa(){
i=2;
}
aa();
alert(i);
})();
(function(){
i=10;
function aa(){
var i=2;
}
aa();
alert(i);
})();
</script>
在同一个js文件中,使用匿名函数,可以定义方法名相同的方法。
在函数里面没有var声明的变量会直接影响全局的变量,是因为在js中,如果某个变量没有var声明,
会自动到上一层作用域中去找这个变量的声明语句,如果找到,就使用,如果没有找到,继续向上查找,
一直查找到全局作用域为止。如果全局中仍然没有这个变量的声明语句,那么会自动在全局作用域进行声明,
这个就是js的作用域链 。
外部访问函数内部的变量是闭包实现的,函数内部的变量访问外部的变量是作用域链实现的
<html>
<script type="text/javascript">
/*作为普通函数来调用时,this的值指向window,
准确的说,this为null,但被解释成window
alert(window.xx);
function t(){
this.xx = 2;
}
t();
alert(window.xx);
*/
/*作为对象的方法来调用
this指向方法的调用者,就是该对象
var obj = {xx:11,yy:22,t:function(){alert(this.xx);}};
obj.t();
var dog = {xx:33};
dog.t = obj.t;
dog.t();
*/
/*this作为方法调用时,this指向其调用者,即母体对象,
不管被调用函数声明时属于方法还是属于函数
var dog = {xx:33};
show = function(){
alert('show=' +this.xx);
}
dog.t = show;
dog.t();
*/
/*函数作为构造函数调用时
js中没有类的概念,创建对象是用构造函数完成
或者直接用json格式来创建对象
new对象发生的步骤
a:系统创建空对象{},空对象的constructor属性指向构造感受
b:把函数的this指向该空对象
c:执行该函数
d:返回该对象
*/
function Pig(){
this.age = 2;
return 'a';
}
var pig = new Pig();
//返回Pig对象,因为函数作为构造函数运行时,
//return的值是忽略的,还是返回对象
</script>
</html>
<html>
<script type="text/javascript">
/*arguments是一个对象,一个长得很像数组的对象*/
/*arguments内容是函数运行时期的实参列表*/
/*arguments.callee 属性代表当前运行的函数*/
/*题目:不用函数名,使用匿名函数,完成递归*/
alert((function(n){
if (n<=1){
return n;
}else{
return n+arguments.callee(n-1);
}
})(100));
/*
函数运行期内,关键的三个函数
1:ao 如果本函数ao上没有属性,则继续去外层函数的ao
上找,直到全局对象,叫做作用域链
2:arguments 每个函数有自己的callee属性,但不向外层
接着找arguments相关属性,不形成链
*/
</script>
</html>
<html>
<script type="text/javascript">
function t1(){}
//t2=function(){}
/*这2种方式效果是不同的
t1是函数声明,全局内得到一个t1变量,值是function
t2只是一个赋值过程,值是右侧的表达式的返回结果,即函数
function(){}在js看来,就和3*3一样,是个表达式,返回一个结果
因此t1,t2两种方式在词法分析时,有着本质区别
前者在词法分析阶段就发挥作用
后者在运行阶段才发挥作用
*/
(function(window,undefined){alert(window);})(window);
</script>
</html>
<html>
<script type="text/javascript">
function a(b){
alert(b);
function b(){
alert(b);
}
b();
}
//a(1);
/*ao{b=fun}*/
function aa(b){
alert(b);
b=function (){
alert(b);
}
b();
}
aa(1);
/*
0:ao={}
1:分析参数 ao={b=undefined},马上变成ao={b=1}
2:分析var声明,没有
3:分析函数声明,没有
(注:b=function(){}是一个赋值过程,在执行期才有用)
*/
/*词法分析
分析3样东西
第一步:先分析参数
第二步:再分析变量声明
第三步:分析函数声明
一个函数能使用的局部变量,就从3步而来
具体步骤:
0:函数运行前的一瞬间,生成active object
1:a.把声明的参数作为ao对象的属性,值都是undefined
b.接收实参,形成ao对应属性的值
2:分析变量声明,如var
如果ao上还没有此变量声明,则把此变量作为ao属性,
值是undefined
如果ao上已经有了此属性,则不做任何影响
3:分析函数声明,如function t(){}
则把此函数作为ao的属性
注:如果此前ao已经有了t属性,则以前的t被覆盖
*/
function t1(age){
alert(age);
}
//t1(1);
function t2(age){
var age = 99;
alert(age);
}
//t2(1);
function t3(g){
var g = 'hello';
alert(g);
function g(){
}
alert(g);
}
//t3();
</script>
</html>
<html>
<script type="text/javascript">
function a(b){
alert(b);
function b(){
alert(b);
}
b();
}
//a(1);
/*ao{b=fun}*/
function aa(b){
alert(b);
b=function (){
alert(b);
}
b();
}
aa(1);
/*
0:ao={}
1:分析参数 ao={b=undefined},马上变成ao={b=1}
2:分析var声明,没有
3:分析函数声明,没有
(注:b=function(){}是一个赋值过程,在执行期才有用)
*/
/*词法分析
分析3样东西
第一步:先分析参数
第二步:再分析变量声明
第三步:分析函数声明
一个函数能使用的局部变量,就从3步而来
具体步骤:
0:函数运行前的一瞬间,生成active object
1:a.把声明的参数作为ao对象的属性,值都是undefined
b.接收实参,形成ao对应属性的值
2:分析变量声明,如var
如果ao上还没有此变量声明,则把此变量作为ao属性,
值是undefined
如果ao上已经有了此属性,则不做任何影响
3:分析函数声明,如function t(){}
则把此函数作为ao的属性
注:如果此前ao已经有了t属性,则以前的t被覆盖
*/
function t1(age){
alert(age);
}
//t1(1);
function t2(age){
var age = 99;
alert(age);
}
//t2(1);
function t3(g){
var g = 'hello';
alert(g);
function g(){
}
alert(g);
}
//t3();
</script>
</html>
<html>
<script type="text/javascript">
/*作用域
在js中,函数嵌套是非常普遍的,在函数嵌套中,
对变量是如何寻找的?
答:首先在函数内部寻找,如果需找不到,则在外层寻找。
直到……全局(window)区域.从里往外寻找
*/
var c=5;
function t1(){
var d=6;
function t2(){
var e =7;
alert(c+d+e);
}
t2();
}
//t1();//18
function t3(){
var d=6;
function t2(){
var e =7;
d =3;
alert(c+d+e);
}
t2();
}
//t3();//15
/*声明变量,var的作用
var 是在函数运行的上下文中,声明一个变量,
如果不加var,则是一个赋值操作,
但是不要狭隘的理解为声明了一个全局变量
*/
//alert(window.d);
//alert(window.e);
function t(){
d=5;//d没有加var,仅仅是一个赋值操作,寻找
//t域内的函数,如果没找到,继续向外寻找……到window
//如果window中还没有d,创建d变量并赋值
var e=6;
}
//t();
//alert(window.d);
//alert(window.e);
function t4 (){
var d;
function t2(){
d=5;
e=6;
}
t2();
}
//t4();
//alert(window.d);//undefined
//alert(d);// d is not defined
//alert(e);
/*
注意:以window.xxx引用全局变量,寻找不到,
作为window的属性不存在,返回undefined。
直接以xxx引用,寻找不到,则报xxx is not defined
*/
var s1='g';
function t5(){
alert(s1);//g
alert(s2);//is not defined
s2 = 'lo';
}
// t5();
/*
在t5中寻找s2,没有找到s2的变量声明,到window上寻找s2的变量声明,
还是没有找到,报is not defined
*/
function t6(){
alert(s1);//g
alert(s2);//undefined
var s2 = 'lo';
}
t6();
/*
解释:
js代码自上而下执行,但是js代码的整体运行分为:
词法分析期和运行期
自上而下执行之前,先有一个词法分析过程。
词法分析t6函数:
声明了s2变量,但是没有对s2赋值,只有在运行期才赋值
因此s2=undefined。
执行t6函数:
alert(s1);//g
alert(s2);//undefined
s2 = 'lo';
*/
</script>
</html>
/**
* 任务实体类
*/
@Entity
@Table(name = "t_task")
public class Task implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private Long id;
private String name;
//计划开始时间
private Date plan_startTime;
private Project project;
//父任务
private Task parent;
// 子任务
private Set<Task> children = new HashSet<Task>();
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Temporal(TemporalType.TIMESTAMP)
public Date getPlan_startTime() {
return plan_startTime;
}
public void setPlan_startTime(Date plan_startTime) {
this.plan_startTime = plan_startTime;
}
@ManyToOne(optional = false, cascade = {CascadeType.REFRESH, CascadeType.MERGE})
@JoinColumn(name = "projectId")
public Project getProject() {
return project;
}
public void setProject(Project project) {
this.project = project;
}
@ManyToOne(cascade = {CascadeType.REFRESH, CascadeType.MERGE})
@JoinColumn(name = "parentId")
public Task getParent() {
return parent;
}
public void setParent(Task parent) {
this.parent = parent;
}
@OrderBy("id ASC")
@OneToMany(mappedBy = "parent", fetch = FetchType.LAZY, cascade = {CascadeType.ALL})
public Set<Task> getChildren() {
return children;
}
public void setChildren(Set<Task> children) {
this.children = children;
}
}
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
public String key();
public String value();
}
@MyAnnotation(key = "k", value = "v")
public class UserAnnotation {
@MyAnnotation(key = "km", value = "vm")
public void sayHello() {
System.out.println("111");
}
public static void main(String[] args) throws Exception {
Class<?> cla = Class
.forName("com.kaishengit.annotation.UserAnnotation");
Method[] methods = cla.getMethods();
boolean flag = cla.isAnnotationPresent(MyAnnotation.class);
System.out.println(flag);
if (flag) {
MyAnnotation mya = (MyAnnotation) cla
.getAnnotation(MyAnnotation.class);
System.out.println(mya.key() + "====" + mya.value());
}
Set<Method> set = new HashSet<Method>();
for (int i = 0; i < methods.length; i++) {
boolean otherflag = methods[i]
.isAnnotationPresent(MyAnnotation.class);
if (otherflag) {
set.add(methods[i]);
System.out.println(methods[i].getName());
}
}
for (Method method : set) {
MyAnnotation name = method.getAnnotation(MyAnnotation.class);
System.out.println(name.key());
System.out.println("value===:" + name.value());
}
}
}
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.kaishengit.util.desfile;
import com.google.gson.Gson;
import javax.crypto.KeyGenerator;
import javax.crypto.CipherInputStream;
import javax.crypto.Cipher;
import javax.crypto.CipherOutputStream;
import java.security.SecureRandom;
import java.security.Key;
import java.io.*;
import java.security.*;
import java.util.ArrayList;
import java.util.List;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
/**
*
* @author Y-T测试成功
*/
public class DesFile3 {
// private static final String k = "24234";
Key key;
public DesFile3() {
getKey("24234");//生成密匙
}
/**
* 根据参数生成KEY
*/
public void getKey(String strKey) {
try {
KeyGenerator _generator = KeyGenerator.getInstance("DES");
_generator.init(new SecureRandom(strKey.getBytes()));
this.key = _generator.generateKey();
_generator = null;
} catch (Exception e) {
throw new RuntimeException("Error initializing SqlMap class. Cause: " + e);
}
}
//加密以byte[]明文输入,byte[]密文输出
private byte[] getEncCode(byte[] byteS) {
byte[] byteFina = null;
Cipher cipher;
try {
cipher = Cipher.getInstance("DES");
cipher.init(Cipher.ENCRYPT_MODE, key);
byteFina = cipher.doFinal(byteS);
} catch (Exception e) {
e.printStackTrace();
} finally {
cipher = null;
}
return byteFina;
}
// 加密String明文输入,String密文输出
public String setEncString(String strMing) {
BASE64Encoder base64en = new BASE64Encoder();
String s = null;
try {
s = base64en.encode(getEncCode(strMing.getBytes("UTF8")));
} catch (Exception e) {
e.printStackTrace();
}
return s;
}
public String setEncString(String strMing, int count) {
BASE64Encoder base64en = new BASE64Encoder();
String s = strMing;
if (s != null) {
for (int i = 0; i < count; i++) {
try {
s = base64en.encode(getEncCode(s.getBytes("UTF8")));
} catch (Exception e) {
e.printStackTrace();
}
}
} else {
return s;
}
return s;
}
// 解密以byte[]密文输入,以byte[]明文输出
public byte[] getDesCode(byte[] byteD) {
Cipher cipher;
byte[] byteFina = null;
try {
cipher = Cipher.getInstance("DES");
cipher.init(Cipher.DECRYPT_MODE, key);
byteFina = cipher.doFinal(byteD);
} catch (Exception e) {
e.printStackTrace();
} finally {
cipher = null;
}
return byteFina;
}
// 解密:以String密文输入,String明文输出
public String setDesString(String strMi) {
BASE64Decoder base64De = new BASE64Decoder();
String s = null;
try {
s = new String(getDesCode(base64De.decodeBuffer(strMi)), "UTF8");
} catch (Exception e) {
e.printStackTrace();
}
return s;
}
public String setDesString(String strMi, int count) {
BASE64Decoder base64De = new BASE64Decoder();
String s = strMi;
if (s != null) {
for (int i = 0; i < count; i++) {
try {
s = new String(getDesCode(base64De.decodeBuffer(s)), "UTF8");
} catch (Exception e) {
e.printStackTrace();
}
}
} else {
return s;
}
return s;
}
/**
* 文件file进行加密并保存目标文件destFile中
*
* @param file 要加密的文件 如c:/test/srcFile.txt
* @param destFile 加密后存放的文件名 如c:/加密后文件.txt
*/
public void fileEncrypt(String file, String destFile) throws Exception {
Cipher cipher = Cipher.getInstance("DES");
// cipher.init(Cipher.ENCRYPT_MODE, getKey());
cipher.init(Cipher.ENCRYPT_MODE, this.key);
InputStream is = new FileInputStream(file);
OutputStream out = new FileOutputStream(destFile);
CipherInputStream cis = new CipherInputStream(is, cipher);
byte[] buffer = new byte[1024];
int r;
while ((r = cis.read(buffer)) > 0) {
out.write(buffer, 0, r);
}
cis.close();
is.close();
out.close();
}
public void fileEncrypt(String file, String destFile, int count) throws Exception {
if(file!=null&&!"".equals(file)&&destFile!=null&&!"".equals(destFile)){
if(count==1){
fileEncrypt( file, destFile);
}else {
String temp="";
String st=file;
for(int i=0;i<count;i++){
if(i!=(count-1)){
temp="src/jia"+System.currentTimeMillis();
fileEncrypt( st, temp);
File f = new File(st);
f.delete();
st=temp;
}else {
fileEncrypt( st, destFile);
File f = new File(st);
f.delete();
}
}
}
}
}
/**
* 文件采用DES算法解密文件
*
* @param file 已加密的文件 如c:/加密后文件.txt
* * @param destFile 解密后存放的文件名 如c:/ test/解密后文件.txt
*/
public void fileDecrypt(String file, String dest) throws Exception {
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.DECRYPT_MODE, this.key);
InputStream is = new FileInputStream(file);
OutputStream out = new FileOutputStream(dest);
CipherOutputStream cos = new CipherOutputStream(out, cipher);
byte[] buffer = new byte[1024];
int r;
while ((r = is.read(buffer)) >= 0) {
cos.write(buffer, 0, r);
}
cos.close();
out.close();
is.close();
}
public void fileDecrypt(String file, String destFile, int count) throws Exception {
if(file!=null&&!"".equals(file)&&destFile!=null&&!"".equals(destFile)){
if(count==1){
fileDecrypt( file, destFile);
}else {
String temp="";
String st=file;
for(int i=0;i<count;i++){
if(i!=(count-1)){
temp="src/jie"+System.currentTimeMillis();
fileDecrypt( st, temp);
File f = new File(st);
f.delete();
st=temp;
}else {
fileDecrypt( st, destFile);
File f = new File(st);
f.delete();
}
}
}
}
}
public static void main(String[] args) throws Exception {
DesFile3 td = new DesFile3();
long begin = System.currentTimeMillis();
td.fileEncrypt("F:\\webservice\\webservice第一部分视频\\02_wsimport的使用.avi", "F:\\webservice\\webservice第一部分视频\\04",2); //加密
long jia = System.currentTimeMillis();
System.out.println((jia-begin)/1000);
long begin1 = System.currentTimeMillis();
// td.fileDecrypt("F:\\webservice\\webservice第一部分视频\\04", "F:\\webservice\\webservice第一部分视频\\04.a"); //解密
td.fileDecrypt("F:\\webservice\\webservice第一部分视频\\04", "F:\\webservice\\webservice第一部分视频\\04.avi",2); //解密
long jie = System.currentTimeMillis();
System.out.println((jie-begin1)/1000);
// List<User> list = new ArrayList<User>();
// User user = new User();
// user.setId(1);
// user.setAge(21);
// user.setName("杨军威");
// User user1 = new User();
// user1.setId(2);
// user1.setAge(23);
// user1.setName("北京");
// list.add(user);
// list.add(user1);
// Gson gson = new Gson();
// String res = gson.toJson(list);
// System.out.println(res);
// System.out.println("加密==" + td.setEncString(res,2));
// // td.setEncString(res);
// System.out.println("解密==" + td.setDesString(td.setEncString(res,2),2));
}
}
package com.kaishengit.util.jackson;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.codehaus.jackson.JsonEncoding;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.node.JsonNodeFactory;
public class JacksonTest {
private static JsonGenerator jsonGenerator = null;
private static ObjectMapper objectMapper = null;
private static AccountBean bean = null;
static {
bean = new AccountBean();
bean.setAddress("china-Guangzhou");
bean.setEmail("hoojo_@126.com");
bean.setId(1);
bean.setName("hoojo");
objectMapper = new ObjectMapper();
try {
jsonGenerator = objectMapper.getJsonFactory().createJsonGenerator(
System.out, JsonEncoding.UTF8);
} catch (IOException e) {
e.printStackTrace();
}
}
// public void init() {}
/*
* public void destory() { try { if (jsonGenerator != null) {
* jsonGenerator.flush(); } if (!jsonGenerator.isClosed()) {
* jsonGenerator.close(); } jsonGenerator = null; objectMapper = null; bean
* = null; System.gc(); } catch (IOException e) { e.printStackTrace(); } }
*/
// JavaBean(Entity/Model)转换成JSON
public static void writeEntityJSON() {
try {
System.out.println("jsonGenerator"); // writeObject可以转换java对象,eg:JavaBean/Map/List/Array等
jsonGenerator.writeObject(bean);
System.out.println();
System.out.println("ObjectMapper"); // writeValue具有和writeObject相同的功能
StringWriter strWriter = new StringWriter();
objectMapper.writeValue(strWriter, bean);
String s = strWriter.toString();
System.out.println("-----------------------");
System.out.println(s);
} catch (IOException e) {
e.printStackTrace();
}
}
// 将Map集合转换成Json字符串
public static void writeMapJSON() {
try {
Map<String, Object> map = new HashMap<String, Object>();
map.put("name", bean.getName());
map.put("account", bean);
bean = new AccountBean();
bean.setAddress("china-Beijin");
bean.setEmail("hoojo@qq.com");
map.put("account2", bean);
System.out.println("jsonGenerator");
jsonGenerator.writeObject(map);
System.out.println("");
System.out.println("objectMapper");
Writer strWriter = new StringWriter();
objectMapper.writeValue(strWriter, map);
System.out.println(strWriter.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
// 将List集合转换成json
public static void writeListJSON() {
try {
List<AccountBean> list = new ArrayList<AccountBean>();
list.add(bean);
bean = new AccountBean();
bean.setId(2);
bean.setAddress("address2");
bean.setEmail("email2");
bean.setName("haha2");
list.add(bean);
System.out.println("jsonGenerator"); // list转换成JSON字符串
jsonGenerator.writeObject(list);
System.out.println();
System.out.println("ObjectMapper"); // 用objectMapper直接返回list转换成的JSON字符串
System.out.println("1###" + objectMapper.writeValueAsString(list));
System.out.print("2###"); // objectMapper list转换成JSON字符串
Writer strWriter = new StringWriter();
objectMapper.writeValue(strWriter, list);
System.out.println(strWriter.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
public static void writeOthersJSON() {
try {
String[] arr = { "a", "b", "c" };
System.out.println("jsonGenerator");
String str = "hello world jackson!"; // byte
jsonGenerator.writeBinary(str.getBytes()); // boolean
jsonGenerator.writeBoolean(true); // null
jsonGenerator.writeNull(); // float
jsonGenerator.writeNumber(2.2f); // char
jsonGenerator.writeRaw("c"); // String
jsonGenerator.writeRaw(str, 5, 10); // String
jsonGenerator.writeRawValue(str, 5, 5); // String
jsonGenerator.writeString(str);
jsonGenerator.writeTree(JsonNodeFactory.instance.POJONode(str));
System.out.println(); // Object
jsonGenerator.writeStartObject();// {
jsonGenerator.writeObjectFieldStart("user");// user:{
jsonGenerator.writeStringField("name", "jackson");// name:jackson
jsonGenerator.writeBooleanField("sex", true);// sex:true
jsonGenerator.writeNumberField("age", 22);// age:22
jsonGenerator.writeEndObject();// }
jsonGenerator.writeArrayFieldStart("infos");// infos:[
jsonGenerator.writeNumber(22);// 22
jsonGenerator.writeString("this is array");// this is array
jsonGenerator.writeEndArray();// ]
jsonGenerator.writeEndObject();// }
AccountBean bean = new AccountBean();
bean.setAddress("address");
bean.setEmail("email");
bean.setId(1);
bean.setName("haha");
// complex Object
jsonGenerator.writeStartObject();// {
jsonGenerator.writeObjectField("user", bean);// user:{bean}
jsonGenerator.writeObjectField("infos", arr);// infos:[array]
jsonGenerator.writeEndObject();// }
} catch (Exception e) {
e.printStackTrace();
}
}
// 将json字符串转换成JavaBean对象
public static void readJson2Entity() {
String json = "{\"address\":\"address\",\"name\":\"haha\",\"id\":1,\"email\":\"email\"}";
try {
AccountBean acc = objectMapper.readValue(json, AccountBean.class);
System.out.println(acc.getName());
System.out.println(acc);
} catch (JsonParseException e) {
e.printStackTrace();
} catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
// 将json字符串转换成List<Map>集合
public static void readJson2List() {
String json = "[{\"address\": \"address2\",\"name\":\"haha2\",\"id\":2,\"email\":\"email2\"},"
+ "{\"address\":\"address\",\"name\":\"haha\",\"id\":1,\"email\":\"email\"}]";
try {
List<LinkedHashMap<String, Object>> list = objectMapper.readValue(
json, List.class);
System.out.println(list.size());
for (int i = 0; i < list.size(); i++) {
Map<String, Object> map = list.get(i);
Set<String> set = map.keySet();
for (Iterator<String> it = set.iterator(); it.hasNext();) {
String key = it.next();
System.out.println(key + ":" + map.get(key));
}
}
} catch (JsonParseException e) {
e.printStackTrace();
} catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
// Json字符串转换成Array数组
public static void readJson2Array() {
String json = "[{\"address\": \"address2\",\"name\":\"haha2\",\"id\":2,\"email\":\"email2\"},"
+ "{\"address\":\"address\",\"name\":\"haha\",\"id\":1,\"email\":\"email\"}]";
try {
AccountBean[] arr = objectMapper.readValue(json,
AccountBean[].class);
System.out.println(arr.length);
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
} catch (JsonParseException e) {
e.printStackTrace();
} catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
// Json字符串转换成Map集合
public static void readJson2Map() {
String json = "{\"success\":true,\"A\":{\"address\": \"address2\",\"name\":\"haha2\",\"id\":2,\"email\":\"email2\"},"
+ "\"B\":{\"address\":\"address\",\"name\":\"haha\",\"id\":1,\"email\":\"email\"}}";
try {
Map<String, Map<String, Object>> maps = objectMapper.readValue(
json, Map.class);
System.out.println(maps.size());
Set<String> key = maps.keySet();
Iterator<String> iter = key.iterator();
while (iter.hasNext()) {
String field = iter.next();
System.out.println(field + ":" + maps.get(field));
}
} catch (JsonParseException e) {
e.printStackTrace();
} catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/*
* public void writeObject2Xml() { //stax2-api-3.0.2.jar
* System.out.println("XmlMapper"); XmlMapper xml = new XmlMapper(); try {
* //javaBean转换成xml //xml.writeValue(System.out, bean); StringWriter sw =
* new StringWriter(); xml.writeValue(sw, bean);
* System.out.println(sw.toString()); //List转换成xml List<AccountBean> list =
* new ArrayList<AccountBean>(); list.add(bean); list.add(bean);
* System.out.println(xml.writeValueAsString(list)); //Map转换xml文档
* Map<String, AccountBean> map = new HashMap<String, AccountBean>();
* map.put("A", bean); map.put("B", bean);
* System.out.println(xml.writeValueAsString(map)); } catch
* (JsonGenerationException e) { e.printStackTrace(); } catch
* (JsonMappingException e) { e.printStackTrace(); } catch (IOException e) {
* e.printStackTrace(); }}
*/
public static void main(String[] args) {
JacksonTest.writeEntityJSON();
// JacksonTest.writeMapJSON();
// JacksonTest.writeListJSON();
// JacksonTest.writeOthersJSON();
// JacksonTest.readJson2Entity();
// JacksonTest.readJson2List();
// JacksonTest.readJson2Array();
//JacksonTest.readJson2Map();
}
}
1.公司和雇员的实体类
@XmlRootElement(name="company")
public class Company {
// @XmlElement(name="cname")
private String cname;
@XmlElement(name="employee")
private List<Employee> employees;
public Company(String cname,List<Employee> employees){
this.cname=cname;
this.employees=employees;
}
public Company(){}
@XmlTransient
public List<Employee> getEmployees() {
return this.employees;
}
public void setEmployees(List<Employee> employees) {
this.employees = employees;
}
// public void addEmployee(Employee employee){
// if(employees==null){
// this.employees=new ArrayList<Employee>();
// }
// this.employees.add(employee);
// }
public String getCname() {
return this.cname;
}
public void setCname(String cname) {
this.cname = cname;
}
}
@XmlType
public class Employee {
@XmlElement(name="name")
private String name;
@XmlElement(name="id")
private String id;
public Employee(String name,String id){
this.id=id;
this.name=name;
}
public Employee(){}
@XmlTransient
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@XmlTransient
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
测试类:
public class Test {
public static void main(String[] args){
Test.test01();
}
public static void test01() {
long l=System.currentTimeMillis();
try {
JAXBContext ctx = JAXBContext.newInstance(Company.class);
Marshaller marshaller = ctx.createMarshaller();
List<Employee> list=new ArrayList<Employee>();
list.add(new Employee("1","1e"));
list.add(new Employee("2", "2e"));
Company c = new Company("cc",list);
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
// marshaller.marshal( c,new FileOutputStream("src/"+l+".xml"));
StringWriter sw = new StringWriter();
marshaller.marshal(c,sw);
System.out.println(sw.toString());
test02(sw.toString());
// Unmarshaller unmarshaller = ctx.createUnmarshaller();
// File file = new File("src/"+l+".xml");
// Company cc = (Company)unmarshaller.unmarshal(file);
// // System.out.println(cc.getCname());
// System.out.println(cc.getEmployees().get(0).getName());
// System.out.println(file.exists());
} catch (JAXBException e) {
e.printStackTrace();
}
}
public static void test02(String xml) {
try {
// String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><company><employee><name>1</name><id>1e</id></employee><employee><name>2</name><id>2e</id></employee><cname>cc</cname></company>";
JAXBContext ctx = JAXBContext.newInstance(Company.class);
Unmarshaller um = ctx.createUnmarshaller();
Company stu = (Company)um.unmarshal(new StringReader(xml));
System.out.println(stu.getEmployees().get(0).getName() +","+stu.getCname());
} catch (JAXBException e) {
e.printStackTrace();
}
}
public static void test03() {
try{
JAXBContext context = JAXBContext.newInstance(Company.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
File file = new File("src/test.xml");
Company c = (Company)unmarshaller.unmarshal(file);
System.out.println(c.getCname());
System.out.println(c.getEmployees().get(0).getName());
}catch (Exception e){
}
// System.out.println(people.age);
}
}
select * from table_name
是查询出table_name 里所有的记录
select * from table_name where column_name like '%%'
是查询出table_name表里column_name 类似于'%%'的记录
由于%是代替所有,‘%%’代替所有,但并不表示代替空值,所以后一条记录和前一条的区别是,前一条是查询所有记录,后一条是查询column_name 值 不为空的所有记录。
%是字符通配付,必须是字符。
select * from table_name 是查询整个表
select * from table_name where column_name like '%%' 查询这个字段 NOT IS NULL
加载Spring配置文件时,如果Spring配置文件中所定义的Bean类实现了ApplicationContextAware 接口,那么在加载Spring配置文件时,会自动调用ApplicationContextAware 接口中的
public void setApplicationContext(ApplicationContext context) throws BeansException
方法,获得ApplicationContext对象。
前提必须在Spring配置文件中指定该类
public class ApplicationContextRegister implements ApplicationContextAware {
private Log log = LogFactory.getLog(getClass());
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
ContextUtils.setApplicationContext(applicationContext);
log.debug("ApplicationContext registed");
}
}
public class ContextUtils {
private static ApplicationContext applicationContext;
private static Log log = LogFactory.getLog(ContextUtils.class);
public static void setApplicationContext(ApplicationContext applicationContext) {
synchronized (ContextUtils.class) {
log.debug("setApplicationContext, notifyAll");
ContextUtils.applicationContext = applicationContext;
ContextUtils.class.notifyAll();
}
}
public static ApplicationContext getApplicationContext() {
synchronized (ContextUtils.class) {
while (applicationContext == null) {
try {
log.debug("getApplicationContext, wait...");
ContextUtils.class.wait(60000);
if (applicationContext == null) {
log.warn("Have been waiting for ApplicationContext to be set for 1 minute", new Exception());
}
} catch (InterruptedException ex) {
log.debug("getApplicationContext, wait interrupted");
}
}
return applicationContext;
}
}
public static Object getBean(String name) {
return getApplicationContext().getBean(name);
}
}
配置文件:<bean class="com.sinotrans.framework.core.support.ApplicationContextRegister" />
正常情况:
- public class AppManager extends ContextLoaderListener implements ServletContextListener {
-
- private ServletContext context;
- private WebApplicationContext webApplicationContext;
-
- public void contextInitialized(ServletContextEvent sce) {
- this.context = sce.getServletContext();
- this.webApplicationContext = WebApplicationContextUtils.getRequiredWebApplicationContext(context);
- this.context.setAttribute("WEBAPPLICATIONCONTEXT", webApplicationContext); }
- HttpSession session = request.getSession();
- WebApplicationContext webApplicationContext = (WebApplicationContext)session.getServletContext().getAttribute("WEBAPPLICATIONCONTEXT");
- UnsubscribeEmailFacade unsubscribeEmailFacade = (UnsubscribeEmailFacade)webApplicationContext.getBean("unsubscribeEmailFacade");
<html>
<head>
<script src="jquery.js" type="text/javascript"></script>
</head>
<body>
<form class="cmxform" id="commentForm" method="get" action="#" style="float:left;position:absolute ;background-color: yellow;width:100%;height:100% " >
<fieldset style="width:100%;height:100%">
<p>
<label for="cusername">姓名</label>
<em>*</em><input id="cusername" name="username" size="25" />
</p>
<p>
<label for="cemail">电子邮件</label>
<em>*</em><input id="cemail" name="email" size="25" />
</p>
<p>
<label for="curl">网址</label>
<em> </em><input id="curl" name="url" size="25" value="" />
</p>
<p>
<label >价格</label>
<em> </em><input id="cprice" name="price" size="25" value="" />
</p>
<p>
<label for="ccomment">你的评论</label>
<em>*</em><textarea id="ccomment" name="comment" cols="22" ></textarea>
</p>
<p>
<input class="submit" type="button" value="提交"/>
<input class="quxiao" type="button" value="取消"/>
</p>
</fieldset>
</form>
<div>
<form>
<input type="text" id="chaxun" /><input type="button" value="查询" />
</form>
<div>
<input type="button" value="全选/全不选" id="CheckedAll"/>
<input type="button" value="反选" id='CheckedRev' />
<input id="add" type="button" value="新增"/>
<input type="button" value="删除" class="deleteall" />
</div>
</div>
<table cellpadding="0" cellspacing="0" border="1" width="100%">
<thead><tr><td>姓名</td><td>电子邮件</td><td>网址</td><td>你的评论</td><td>价格</td><td>编辑</td><td>删除</td></tr></thead>
<tbody>
<tr></tr>
</tbody>
<tfoot>
<tr><td>总价</td><td colspan="6">0</td></tr>
</tfoot>
</table>
</body>
<script type="text/javascript">
$(document).ready(function(){
// $("#commentForm").validate({meta: "validate"});
$("#commentForm").hide();
$("#add").bind("click",function(){
if($("#commentForm").is(":visible")){
$("#commentForm").hide();
}else{
$("#commentForm").show();
}
})
var num = 1;
$(".submit").click(function(){
$("#commentForm").hide();
var name = $('#cusername').val();
var email = $('#cemail').val();
var url = $('#curl').val();
var price = $('#cprice').val();
var comment = $('#ccomment').val();
var tr = $('<tr class="'+num+'"><td class="jsname"><input type="checkbox" value="'+num+'"/>'+name+'</td><td class="jsemail">'+email+'</td><td class="jsurl">'+url+'</td><td class="jscomment">'+comment+'</td><td class="jsprice" id="'+num+'">'+price+'</td><td><a href="#" class="edit">编辑</a></td><td><a href="#" class="delete">删除</a></td></tr>');
$('tbody tr:eq(0)').after(tr);
num++;
});
$(".quxiao").click(function(){
$("#commentForm").hide();
});
$('.delete').live('click',function(){
$(this).parent().parent().remove();
});
$('.edit').live('click',function(){
var tr=$(this).parent().parent();
var name = tr.children('.jsname').text();
var email = tr.children('.jsemail').text();
var url = tr.children('.jsurl').text();
var comment = tr.children('.jscomment').text();
var price = tr.children('.jsprice').text();
$('#cusername').attr('value',name);
$('#cemail').attr('value',email);
$('#curl').attr('value',url);
$('#cprice').attr('value',price);
$('#ccomment').attr('value',comment);
$("#commentForm").show();
$(this).parent().parent().remove();
});
$('.deleteall').click(function(){
$('input[type="checkbox"]:checked').each(function(){
$(this).parent().parent().remove();
});
});
var a = true;
$("#CheckedAll").click(function(){
//所有checkbox跟着全选的checkbox走。
if(a){
$('input[type="checkbox"]:checkbox').attr("checked", true);
a = false;
}else {
$('input[type="checkbox"]:checkbox').attr("checked", false);
a=true;
}
});
$("#CheckedRev").click(function(){
$('input[type="checkbox"]:checkbox').each(function(){
this.checked=!this.checked;
});
});
});
</script>
</html>
myschema文件如下:<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="
http://www.w3.org/2001/XMLSchema"
targetNamespace="
http://www.example.org/myschema"
xmlns:tns="
http://www.example.org/myschema"
elementFormDefault="qualified">
<element name="user">
<complexType>
<sequence>
<element name="id" type="int"/>
<element name="username" type="string"/>
<element name="time" type="date"/>
</sequence>
</complexType>
</element>
</schema>
xml文件如下1:
<?xml version="1.0" encoding="UTF-8"?>
<user xmlns="
http://www.example.org/01"
xmlns:xsi="
http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.example.org/01">
<id>1</id>
<username>zhangsan</username>
<born>1989-12-22</born>
</user>
xml文件2如下:
<?xml version="1.0" encoding="UTF-8"?>
<user xmlns="
http://www.example.org/01"
xmlns:xsi="
http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="01.xsd">
<id>11</id>
<username>lisi</username>
<born>1988-11-11</born>
</user>
摘要: --
开发流程:
一、先写schema或者wsdl文件
(1)新建一个项目作为服务端,在src目录下简历文件夹META-INF/wsdl/mywsdl.wsdl文件。(2)在mywsdl.wsdl文件中编写自己的内容,如下:
<?xml version="1.0"
encoding="UTF-8" standalone="no"?>
<wsdl:d...
阅读全文
@WebService
public interface IMyService {
@WebResult(name="addResult")
public int add(@WebParam(name="a")int a,@WebParam(name="b")int b);
@WebResult(name="user")
public User addUser(@WebParam(name="user")User user);
@WebResult(name="user")
public User login(@WebParam(name="username")String username,
@WebParam(name="password")String password)throws UserException;
@WebResult(name="user")
public List<User> list(@WebParam(header=true,name="authInfo")String authInfo);
}
@XmlRootElement
public class User {
private int id;
private String username;
private String nickname;
private String password;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public User(int id, String username, String nickname, String password) {
super();
this.id = id;
this.username = username;
this.nickname = nickname;
this.password = password;
}
public User() {
super();
}
}
public class MyServer {
public static void main(String[] args) {
Endpoint.publish("http://localhost:8989/ms", new MyServiceImpl());
}
}
@WebService(endpointInterface="org.soap.service.IMyService")
@HandlerChain(file="handler-chain.xml")
public class MyServiceImpl implements IMyService {
private static List<User> users = new ArrayList<User>();
public MyServiceImpl() {
users.add(new User(1,"admin","","111111"));
}
@Override
public int add(int a, int b) {
System.out.println("a+b="+(a+b));
return a+b;
}
@Override
public User addUser(User user) {
users.add(user);
return user;
}
@Override
public User login(String username, String password) throws UserException{
for(User user:users) {
if(username.equals(user.getUsername())&&password.equals(user.getPassword()))
return user;
}
throw new UserException("");
}
@Override
public List<User> list(String authInfo) {
System.out.println(authInfo);
return users;
}
}
public class TestSoap {
private static String ns = "http://service.soap.org/";
private static String wsdlUrl = "http://localhost:8989/ms?wsdl";
public static void main(String[] args){
TestSoap.test03();
}
@Test
public static void test01() {
try {
//1�������创建消息工厂���
MessageFactory factory = MessageFactory.newInstance();
//2����根据消息工厂创建SoapMessage
SOAPMessage message = factory.createMessage();
//3�����创建SOAPPart
SOAPPart part = message.getSOAPPart();
//4��获取SOAPENvelope
SOAPEnvelope envelope = part.getEnvelope();
//5��可以通过SoapEnvelope有效的获取相应的Body和Header等信息
SOAPBody body = envelope.getBody();
//6���根据Qname创建相应的节点(QName就是一个带有命名空间的节点)���������ռ��)
QName qname = new QName("http://java.zttc.edu.cn/webservice",
"add","ns");//<ns:add xmlns="http://java.zttc.edu.cn/webservice"/>
//�如果使用以下方式进行设置,会见<>转换为<和>
//body.addBodyElement(qname).setValue("<a>1</a><b>2</b>");
SOAPBodyElement ele = body.addBodyElement(qname);
ele.addChildElement("a").setValue("22");
ele.addChildElement("b").setValue("33");
//打印消息信息
message.writeTo(System.out);
} catch (SOAPException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
@Test//基于soap的消息传递
public static void test02() {
try {
//1���创建服务(Service)
URL url = new URL(wsdlUrl);
QName sname = new QName(ns,"MyServiceImplService");
Service service = Service.create(url,sname);
//2����创建Dispatch
Dispatch<SOAPMessage> dispatch = service.createDispatch(new QName(ns,"MyServiceImplPort"),
SOAPMessage.class, Service.Mode.MESSAGE);
//3����创建SOAPMessage
SOAPMessage msg = MessageFactory.newInstance().createMessage();
SOAPEnvelope envelope = msg.getSOAPPart().getEnvelope();
SOAPBody body = envelope.getBody();
//4���创建QName来指定消息中传递数据����
QName ename = new QName(ns,"add","nn");//<nn:add xmlns="xx"/>
SOAPBodyElement ele = body.addBodyElement(ename);
ele.addChildElement("a").setValue("22");
ele.addChildElement("b").setValue("33");
msg.writeTo(System.out);
System.out.println("\n invoking.....");
//5�通过Dispatch传递消息,会返回响应消息
SOAPMessage response = dispatch.invoke(msg);
response.writeTo(System.out);
System.out.println("\n----------------------------------------");
//��将响应的消息转换为dom对象��
Document doc = response.getSOAPPart().getEnvelope().getBody().extractContentAsDocument();
String str = doc.getElementsByTagName("addResult").item(0).getTextContent();
System.out.println(str);
} catch (SOAPException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
@Test
public static void test03() {
try {
//1�����创建服务(Service)
URL url = new URL(wsdlUrl);
QName sname = new QName(ns,"MyServiceImplService");
Service service = Service.create(url,sname);
//2���创建Dispatch(通过源数据的方式传递)
Dispatch<Source> dispatch = service.createDispatch(new QName(ns,"MyServiceImplPort"),
Source.class, Service.Mode.PAYLOAD);
//3���根据用户对象创建相应的xml
User user = new User(3,"zs","张三","11111");
//编排user对象
JAXBContext ctx = JAXBContext.newInstance(User.class);
Marshaller mar = ctx.createMarshaller();
//不会再创建xml的头信息
mar.setProperty(Marshaller.JAXB_FRAGMENT, true);
StringWriter writer= new StringWriter();
mar.marshal(user, writer);
System.out.println("writer====="+writer);
//4、封装相应的part addUser
String payload = "<xs:addUser xmlns:xs=\""+ns+"\">"+writer.toString()+"</xs:addUser>";
System.out.println("payload====="+payload);
StreamSource rs = new StreamSource(new StringReader(payload));
//5�通过dispatch传递payload
Source response = (Source)dispatch.invoke(rs);
//6�将Source转化为DOM进行操作,使用Transform对象转换
Transformer tran = TransformerFactory.newInstance().newTransformer();
DOMResult result = new DOMResult();
tran.transform(response, result);
//7���处理相应信息(通过xpath处理)
XPath xpath = XPathFactory.newInstance().newXPath();
NodeList nl = (NodeList)xpath.evaluate("//user", result.getNode(),XPathConstants.NODESET);
User ru = (User)ctx.createUnmarshaller().unmarshal(nl.item(0));
System.out.println(ru.getNickname());
} catch (IOException e) {
e.printStackTrace();
} catch (JAXBException e) {
e.printStackTrace();
} catch (TransformerConfigurationException e) {
e.printStackTrace();
} catch (TransformerFactoryConfigurationError e) {
e.printStackTrace();
} catch (TransformerException e) {
e.printStackTrace();
} catch (XPathExpressionException e) {
e.printStackTrace();
}
}
schema文件:
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="
http://www.w3.org/2001/XMLSchema"
targetNamespace="
http://www.example.org/01"
xmlns:tns="
http://www.example.org/01"
elementFormDefault="qualified">
<element name="user">
<complexType>
<sequence>
<element name="id" type="int"/>
<element name="username" type="string"/>
<element name="born" type="date"/>
</sequence>
</complexType>
</element>
</schema>
xml文件1:
<?xml version="1.0" encoding="UTF-8"?>
<user xmlns="
http://www.example.org/01"
xmlns:xsi="
http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.example.org/01">
<id>1</id>
<username>zhangsan</username>
<born>1989-12-22</born>
</user>
xml文件2:
<?xml version="1.0" encoding="UTF-8"?>
<user xmlns="
http://www.example.org/01"
xmlns:xsi="
http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="01.xsd">
<id>11</id>
<username>lisi</username>
<born>1988-11-11</born>
</user>
schema文件2:
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.example.org/02"
xmlns:tns="http://www.example.org/02" elementFormDefault="qualified">
<element name="books">
<complexType>
<!-- maxOccurs表示最大出现次数 -->
<sequence maxOccurs="unbounded">
<element name="book">
<complexType>
<sequence minOccurs="1" maxOccurs="unbounded">
<element name="title" type="string" />
<element name="content" type="string" />
<choice>
<element name="author" type="string" />
<element name="authors">
<complexType>
<all><!-- 每个元素只能出现一次 -->
<element name="author" type="string"/>
</all>
</complexType>
</element>
</choice>
</sequence>
<attribute name="id" type="int" use="required"/>
</complexType>
</element>
</sequence>
</complexType>
</element>
</schema>
xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<book:books xmlns:book="
http://www.example.org/02"
xmlns:xsi="
http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="02.xsd">
<book:book id="1">
<book:title>Java in action</book:title>
<book:content>Java is good</book:content>
<book:author>Bruce</book:author>
</book:book>
<book:book id="2">
<book:title>SOA in action</book:title>
<book:content>soa is difficult</book:content>
<book:authors>
<book:author>Jike</book:author>
</book:authors>
</book:book>
</book:books>
schema文件3:
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="
http://www.w3.org/2001/XMLSchema"
targetNamespace="
http://www.example.org/04"
xmlns:tns="
http://www.example.org/04"
elementFormDefault="qualified">
<element name="person" type="tns:personType"/>
<complexType name="personType">
<sequence>
<element name="name" type="string"/>
<element name="age" type="tns:ageType"/>
<element name="email" type="tns:emailType"/>
</sequence>
<attribute name="sex" type="tns:sexType"/>
</complexType>
<simpleType name="emailType">
<restriction base="string">
<pattern value="(\w+\.*)*\w+@\w+\.[A-Za-z]{2,6}"/>
<minLength value="6"/>
<maxLength value="255"/>
</restriction>
</simpleType>
<simpleType name="ageType">
<restriction base="int">
<minInclusive value="1"/>
<maxExclusive value="150"/>
</restriction>
</simpleType>
<simpleType name="sexType">
<restriction base="string">
<enumeration value="男"/>
<enumeration value="女"/>
</restriction>
</simpleType>
</schema>
xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<person xmlns="
http://www.example.org/04"
xmlns:xsi="
http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.example.org/04" sex="男">
<name>搜索</name>
<age>149</age>
<email>sadf@sdf.css</email>
</person>
schema文件4:
classroom.dtd文件:<?xml version="1.0" encoding="UTF-8"?>
<!ELEMENT classroom (claName,grade,students)>
<!ATTLIST classroom id ID #REQUIRED>
<!ELEMENT claName (#PCDATA)>
<!ELEMENT grade (#PCDATA)>
<!ELEMENT students (student+)>
<!ELEMENT student (id,stuName,age)>
<!ELEMENT id (#PCDATA)>
<!ELEMENT stuName (#PCDATA)>
<!ELEMENT age (#PCDATA)>
classroom.xml文件:<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE classroom SYSTEM "classroom.dtd">
<classroom id="c1">
<claName>10计算机应用技术</claName>
<grade>2010</grade>
<students>
<student>
<id>1</id>
<stuName>zhangsan</stuName>
<age>12</age>
</student>
<student>
<id>2</id>
<stuName>lisi</stuName>
<age>122</age>
</student>
</students>
</classroom>
private static String ns = "
http://service.soap.org/";
private static String wsdlUrl = "
http://localhost:8989/ms?wsdl";public static void test02() {
try {
//1���创建服务(Service)
URL url = new URL(wsdlUrl);
QName sname = new QName(ns,"MyServiceImplService");
Service service = Service.create(url,sname);
//2����创建Dispatch
Dispatch<SOAPMessage> dispatch = service.createDispatch(new QName(ns,"MyServiceImplPort"),
SOAPMessage.class, Service.Mode.MESSAGE);
//3����创建SOAPMessage
SOAPMessage msg = MessageFactory.newInstance().createMessage();
SOAPEnvelope envelope = msg.getSOAPPart().getEnvelope();
SOAPBody body = envelope.getBody();
//4���创建QName来指定消息中传递数据����
QName ename = new QName(ns,"add","nn");//<nn:add xmlns="xx"/>
SOAPBodyElement ele = body.addBodyElement(ename);
ele.addChildElement("a").setValue("22");
ele.addChildElement("b").setValue("33");
msg.writeTo(System.out);
System.out.println("\n invoking.....");
//5�通过Dispatch传递消息,会返回响应消息
SOAPMessage response = dispatch.invoke(msg);
response.writeTo(System.out);
System.out.println("\n----------------------------------------");
//��将响应的消息转换为dom对象��
Document doc = response.getSOAPPart().getEnvelope().getBody().extractContentAsDocument();
String str = doc.getElementsByTagName("addResult").item(0).getTextContent();
System.out.println(str);
} catch (SOAPException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void test06() {
InputStream is = null;
try {
is = TestStax.class.getClassLoader().getResourceAsStream("books.xml");
//创建文档处理对象
DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
//通过DocumentBuilder创建doc的文档对象
Document doc = db.parse(is);
//创建XPath
XPath xpath = XPathFactory.newInstance().newXPath();
//第一个参数就是xpath,第二参数就是文档
NodeList list = (NodeList)xpath.evaluate("//book[@category='WEB']", doc,XPathConstants.NODESET);
for(int i=0;i<list.getLength();i++) {
//遍历输出相应的结果
Element e = (Element)list.item(i);
System.out.println(e.getElementsByTagName("title").item(0).getTextContent());
}
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (XPathExpressionException e) {
e.printStackTrace();
} finally {
try {
if(is!=null) is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Test
public static void test07() {
try {
XMLStreamWriter xsw = XMLOutputFactory.newInstance().createXMLStreamWriter(System.out);
xsw.writeStartDocument("UTF-8","1.0");
xsw.writeEndDocument();
String ns = "
http://11:dd";
xsw.writeStartElement("nsadfsadf","person",ns);
xsw.writeStartElement(ns,"id");
xsw.writeCharacters("1");
xsw.writeEndElement();
xsw.writeEndElement();
xsw.flush();
xsw.close();
} catch (XMLStreamException e) {
e.printStackTrace();
} catch (FactoryConfigurationError e) {
e.printStackTrace();
}
}
@Test
public static void test08() {
InputStream is = null;
try {
is = TestStax.class.getClassLoader().getResourceAsStream("books.xml");
//创建文档处理对象
DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
//通过DocumentBuilder创建doc的文档对象
Document doc = db.parse(is);
//创建XPath
XPath xpath = XPathFactory.newInstance().newXPath();
Transformer tran = TransformerFactory.newInstance().newTransformer();
tran.setOutputProperty(OutputKeys.ENCODING,"UTF-8");
tran.setOutputProperty(OutputKeys.INDENT, "yes");
//第一个参数就是xpath,第二参数就是文档
NodeList list = (NodeList)xpath.evaluate("//book[title='Learning XML']", doc,XPathConstants.NODESET);
//获取price节点
Element be = (Element)list.item(0);
Element e = (Element)(be.getElementsByTagName("price").item(0));
e.setTextContent("333.9");
Result result = new StreamResult(System.out);
//通过tranformer修改节点
tran.transform(new DOMSource(doc), result);
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (XPathExpressionException e) {
e.printStackTrace();
} catch (TransformerConfigurationException e) {
e.printStackTrace();
} catch (TransformerFactoryConfigurationError e) {
e.printStackTrace();
} catch (TransformerException e) {
e.printStackTrace();
} finally {
try {
if(is!=null) is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void test05() {
XMLInputFactory factory = XMLInputFactory.newInstance();
InputStream is = null;
try {
is = TestStax.class.getClassLoader().getResourceAsStream("books.xml");
//基于Filter的过滤方式,可以有效的过滤掉不用进行操作的节点,效率会高一些
XMLEventReader reader = factory.createFilteredReader(factory.createXMLEventReader(is),
new EventFilter() {
@Override
public boolean accept(XMLEvent event) {
//返回true表示会显示,返回false表示不显示
if(event.isStartElement()) {
String name = event.asStartElement().getName().toString();
if(name.equals("title")||name.equals("price"))
return true;
}
return false;
}
});
int num = 0;
while(reader.hasNext()) {
//通过XMLEvent来获取是否是某种节点类型
XMLEvent event = reader.nextEvent();
if(event.isStartElement()) {
//通过event.asxxx转换节点
String name = event.asStartElement().getName().toString();
if(name.equals("title")) {
System.out.print(reader.getElementText()+":");
}
if(name.equals("price")) {
System.out.print(reader.getElementText()+"\n");
}
}
num++;
}
System.out.println(num);
} catch (XMLStreamException e) {
e.printStackTrace();
} finally {
try {
if(is!=null) is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void test04() {
XMLInputFactory factory = XMLInputFactory.newInstance();
InputStream is = null;
try {
is = TestStax.class.getClassLoader().getResourceAsStream("books.xml");
//基于迭代模型的操作方式
XMLEventReader reader = factory.createXMLEventReader(is);
int num = 0;
while(reader.hasNext()) {
//通过XMLEvent来获取是否是某种节点类型
XMLEvent event = reader.nextEvent();
if(event.isStartElement()) {
//通过event.asxxx转换节点
String name = event.asStartElement().getName().toString();
if(name.equals("title")) {
System.out.print(reader.getElementText()+":");
}
if(name.equals("price")) {
System.out.print(reader.getElementText()+"\n");
}
}
num++;
}
System.out.println(num);
} catch (XMLStreamException e) {
e.printStackTrace();
} finally {
try {
if(is!=null) is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void test01() {
XMLInputFactory factory = XMLInputFactory.newInstance();
InputStream is = null;
try {
is = TestStax.class.getClassLoader().getResourceAsStream("books.xml");
XMLStreamReader reader = factory.createXMLStreamReader(is);
while(reader.hasNext()) {
// System.out.println("------------------------------------------------");
int type = reader.next();
System.out.println("type---"+type);
//判断节点类型是否是开始或者结束或者文本节点,之后根据情况及进行处理
if(type==XMLStreamConstants.START_ELEMENT) {//==1,指示事件是一个开始元素
System.out.println(reader.getName());
String name = reader.getName().toString();
if("book".equals(name)){
System.out.println(reader.getAttributeName(0)+":"+reader.getAttributeValue(0));
}else if("title".equals(name)){
System.out.println(reader.getAttributeName(0)+":"+reader.getAttributeValue(0));
}
// System.out.println("==1,指示事件是一个开始元素");
} else if(type==XMLStreamConstants.CHARACTERS) {//==4指示事件是一些字符
System.out.println(reader.getText().trim());
// System.out.println("==4指示事件是一些字符");
} else if(type==XMLStreamConstants.END_ELEMENT) {//==2,指示事件是一个结束元素
System.out.println("/"+reader.getName());
// System.out.println("==2,指示事件是一个结束元素");
}
//else if(type==XMLStreamConstants.ATTRIBUTE){
// int count = reader.getAttributeCount();
// System.out.println("count========"+count);
// if(count>0){
// int i=0;
// int[] arr = new int[count];
// while(i<count){
// arr[i]=i;
// i++;
// }
// for(int a : arr){
// System.out.println(reader.getAttributeValue(a));
// }
// }
// }
}
} catch (XMLStreamException e) {
e.printStackTrace();
} finally {
try {
if(is!=null) is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
学生类
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class Student {
private int id;
private String name;
private int age;
private Classroom classroom;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Classroom getClassroom() {
return classroom;
}
public void setClassroom(Classroom classroom) {
this.classroom = classroom;
}
public Student(int id, String name, int age, Classroom classroom) {
super();
this.id = id;
this.name = name;
this.age = age;
this.classroom = classroom;
}
public Student() {
super();
}
}
教室类
public class Classroom {
private int id;
private String name;
private int grade;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getGrade() {
return grade;
}
public void setGrade(int grade) {
this.grade = grade;
}
public Classroom(int id, String name, int grade) {
super();
this.id = id;
this.name = name;
this.grade = grade;
}
public Classroom() {
super();
// TODO Auto-generated constructor stub
}
}
测试类:
public class TestJaxb {
public static void main(String[] args){
TestJaxb.test02();
}
@Test
public static void test01() {//测试对象转换xml字符串
try {
JAXBContext ctx = JAXBContext.newInstance(Student.class);
Marshaller marshaller = ctx.createMarshaller();
Student stu = new Student(1,"张三",21,new Classroom(1,"10计算机应用技术",2010));
marshaller.marshal(stu, System.out);
} catch (JAXBException e) {
e.printStackTrace();
}
}
@Test
public static void test02() {//测试xml字符串转换对象
try {
String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><student><age>21</age><classroom><grade>2010</grade><id>1</id><name>10计算机应用技术</name></classroom><id>1</id><name>张三</name></student>";
JAXBContext ctx = JAXBContext.newInstance(Student.class);
Unmarshaller um = ctx.createUnmarshaller();
Student stu = (Student)um.unmarshal(new StringReader(xml));
System.out.println(stu.getName()+","+stu.getClassroom().getName());
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
1简历webservice服务的步骤:
(1)服务器的建立:1:创建接口SEI(Service Endpoint Interface)
@WebService()
public interface IMyService
{
@WebResult(name="addResult")
public int add(@WebParam(name="a")int
a,@WebParam(name="b")int b);
@WebResult(name="minusResult")
public int minus(@WebParam(name="a")int
a,@WebParam(name="b")int b);
@WebResult(name="loginUser")
public User login(@WebParam(name="username")String
username,@WebParam(name="password")String password);
}
2:创建实现类SIB(Service inplemention Bean)
@WebService(endpointInterface="org.zttc.service.IMyService")
public class MyServiceImpl
implements IMyService {
@Override
public int add(int a, int b) {
System.out.println(a+"+"+b+"="+(a+b));
return a+b;
}
@Override
public int minus(int a, int b) {
System.out.println(a+"-"+b+"="+(a-b));
return a-b;
}
@Override
public User login(String username, String password) {
System.out.println(username+" is logining");
User user = new User();
user.setId(1);
user.setUsername(username);
user.setPassword(password);
return user;
}
}
3:开启服务
public class MyServer {
public
static void main(String[] args) {
String
address = "http://localhost:8888/ns";
Endpoint.publish(address,
new MyServiceImpl());
}
}
在浏览器地址栏中输入; http://localhost:8888/ns?wsdl,看到页面上出现xml文件。
(2)客户端的建立:
public class TestClient {
public
static void main(String[] args) {
try
{
创建访问wsdl服务地址的url
URL
url = new URL("http://localhost:8888/ns?wsdl");
通过qname指明服务的具体信息
QName
sname = new QName("http://service.zttc.org/",
"MyServiceImplService");
创建服务
Service
service = Service.create(url,sname);
实现接口
IMyService
ms = service.getPort(IMyService.class);
System.out.println(ms.add(12,33));
}
catch (MalformedURLException e) {
e.printStackTrace();
}
}
}
3.wsdl的有关参数:
types:用来定义访问的类型
message:SOAP
portType:指明服务器的接口,并且通过operation绑定相应的in和out的消息:其中in表示参数,out表示返回值
binding:指定传递消息所使用的格式
service:指定服务所发布的名称
4:dtd的例子:
classroom.dtd
<?xml version="1.0"
encoding="UTF-8"?>
<!ELEMENT classroom
(claName,grade,students)>
<!ATTLIST classroom id ID #REQUIRED>
<!ELEMENT claName (#PCDATA)>
<!ELEMENT grade (#PCDATA)>
<!ELEMENT students (student+)>
<!ELEMENT student (id,stuName,age)>
<!ELEMENT id (#PCDATA)>
<!ELEMENT stuName (#PCDATA)>
<!ELEMENT age (#PCDATA)>
classroom.xml
<?xml version="1.0"
encoding="UTF-8"?>
<!DOCTYPE classroom SYSTEM
"classroom.dtd">
<classroom id="c1">
<claName>10计算机应用技术</claName>
<grade>2010</grade>
<students>
<student>
<id>1</id>
<stuName>zhangsan</stuName>
<age>12</age>
</student>
<student>
<id>2</id>
<stuName>lisi</stuName>
<age>122</age>
</student>
</students>
</classroom>
1.得到访问的文件地址
<script type="text/javascript">
with(location){
var qs = search.substring(1);
var hostName = hostname; //unavailable when viewing from a local file
var url = href;
}
alert(qs);
alert(hostName);
alert(url);
</script>
<script type="text/javascript">
// == 表示两个对象的toString相等
//===表示两个对象的类型相等且值相等。
alert(null == undefined); //true
alert(null === undefined); //false
alert("NaN" == NaN); //false
alert("NaN" === NaN); //false
alert(NaN == NaN); //false
alert(NaN === NaN); //false
alert(NaN != NaN); //true
alert(NaN !== NaN); //true
alert(false == 0); //true
alert(false === 0); //false
alert(true == 1); //true
alert(true === 1); //false
alert(null == 0); //false
alert(undefined == 0); //false
alert(5 == "5"); //true
alert(5 === "5"); //false
</script>
<script type="text/javascript">
alert(null == undefined); //true
alert(null === undefined); //false
alert("NaN" == NaN); //false
alert("NaN" === NaN); //false
alert(NaN == NaN); //false
alert(NaN === NaN); //false
alert(NaN != NaN); //true
alert(NaN !== NaN); //true
alert(false == 0); //true
alert(false === 0); //false
alert(true == 1); //true
alert(true === 1); //false
alert(null == 0); //false
alert(undefined == 0); //false
alert(5 == "5"); //true
alert(5 === "5"); //false
</script>
<script type="text/javascript">
var result1 = ("55" != 55); //false ?equal because of conversion
var result2 = ("55" !== 55); //true ?not equal because different data types
alert(result1);
alert(result2);
var result1 = ("55" == 55); //true ?equal because of conversion
var result2 = ("55" === 55); //false ?not equal because different data types
</script>
得到window中所有的事件
<script type="text/javascript">
for (var propName in window) {
document.write(propName);
document.write("<br />");
}
</script>
<script type="text/javascript">
for (var propName in window) {
document.write(propName);
document.write("<br />");
}
</script>
方法参数数组
<script type="text/javascript">
function sayHi() {
alert("Hello " + arguments[0] + ", " + arguments[1]);
}
sayHi("Nicholas", "how are you today?");
function howManyArgs() {
alert(arguments.length);
}
howManyArgs("string", 45); //2
howManyArgs(); //0
howManyArgs(12); //1 </script>
<script type="text/javascript">
function sayHi() {
alert("Hello " + arguments[0] + ", " + arguments[1]);
}
sayHi("Nicholas", "how are you today?");
</script>
null的类型
<script type="text/javascript">
var car = null;
alert(typeof car); //"object"
alert(null == undefined); //true </script>
<script type="text/javascript">
var car = null;
alert(typeof car); //"object"
</script>
1 Javascript数组转换为CSV格式
首先考虑如下的应用场景,有一个Javscript的字符型(或者数值型)数组,现在需要转换为以逗号分割的CSV格式文件。则我们可以使用如下的小技巧,代码如下:
- var fruits = ['apple', 'peaches', 'oranges', 'mangoes'];
- var str = fruits.valueOf();
输出:apple,peaches,oranges,mangoes
其中,valueOf()方法会将Javascript数组转变为逗号隔开的字符串。要注意的是,如果想不使用逗号分割,比如用|号分割,则请使用join方法,如下:
- var fruits = ['apple', 'peaches', 'oranges', 'mangoes'];
- var str = fruits.join("|");
输出: apple|peaches|oranges|mangoes
2 将CSV格式重新转换回Javscript数组
那么如何将一个CSV格式的字符串转变回Javascript数组呢?可以使用split()方法,就可以使用任何指定的字符去分隔,代码如下:
- var str = "apple, peaches, oranges, mangoes";
- var fruitsArray = str.split(",");
输出 fruitsArray[0]: apple
3 根据索引移除数组中的某个元素
假如需要从Javascript数组中移除某个元素,可以使用splice方法,该方法将根据传入参数n,移除数组中移除第n个元素(Javascript数组中从第0位开始计算)。
- function removeByIndex(arr, index) {
- arr.splice(index, 1);
- }
- test = new Array();
- test[0] = 'Apple';
- test[1] = 'Ball';
- test[2] = 'Cat';
- test[3] = 'Dog';
- alert("Array before removing elements: "+test);
- removeByIndex(test, 2);
- alert("Array after removing elements: "+test);
则最后输出的为Apple,Ball,Dog
4 根据元素的值移除数组元素中的值
下面这个技巧是很实用的,是根据给定的值去删除数组中的元素,代码如下:
- function removeByValue(arr, val) {
- for(var i=0; i<arr.length; i++) {
- if(arr[i] == val) {
- arr.splice(i, 1);
- break;
- }
- }
- }
-
- var somearray = ["mon", "tue", "wed", "thur"]
-
- removeByValue(somearray, "tue");
-
-
当然,更好的方式是使用prototype的方法去实现,如下代码:
- Array.prototype.removeByValue = function(val) {
- for(var i=0; i<this.length; i++) {
- if(this[i] == val) {
- this.splice(i, 1);
- break;
- }
- }
- }
-
- var somearray = ["mon", "tue", "wed", "thur"]
- somearray.removeByValue("tue");
5 通过字符串指定的方式动态调用某个方法
有的时候,需要在运行时,动态调用某个已经存在的方法,并为其传入参数。这个如何实现呢?下面的代码可以:
- var strFun = "someFunction";
- var strParam = "this is the parameter";
- var fn = window[strFun];
-
-
- fn(strParam);
6 产生1到N的随机数
- var random = Math.floor(Math.random() * N + 1);
-
-
- var random = Math.floor(Math.random() * 10 + 1);
-
-
- var random = Math.floor(Math.random() * 100 + 1);
7 捕捉浏览器关闭的事件
我们经常希望在用户关闭浏览器的时候,提示用户要保存尚未保存的东西,则下面的这个Javascript技巧是十分有用的,代码如下:
- <script language="javascript">
- function fnUnloadHandler() {
-
- alert("Unload event.. Do something to invalidate users session..");
- }
- </script>
- <body onbeforeunload="fnUnloadHandler()">
- ………
- </body>
就是编写onbeforeunload()事件的代码即可
8 检查是否按了回退键
同样,可以检查用户是否按了回退键,代码如下:
- window.onbeforeunload = function() {
- return "You work will be lost.";
- };
9 检查表单数据是否改变
有的时候,需要检查用户是否修改了一个表单中的内容,则可以使用下面的技巧,其中如果修改了表单的内容则返回true,没修改表单的内容则返回false。代码如下:
- function formIsDirty(form) {
- for (var i = 0; i < form.elements.length; i++) {
- var element = form.elements[i];
- var type = element.type;
- if (type == "checkbox" || type == "radio") {
- if (element.checked != element.defaultChecked) {
- return true;
- }
- }
- else if (type == "hidden" || type == "password" ||
- type == "text" || type == "textarea") {
- if (element.value != element.defaultValue) {
- return true;
- }
- }
- else if (type == "select-one" || type == "select-multiple") {
- for (var j = 0; j < element.options.length; j++) {
- if (element.options[j].selected !=
- element.options[j].defaultSelected) {
- return true;
- }
- }
- }
- }
- return false;
- }
- window.onbeforeunload = function(e) {
- e = e || window.event;
- if (formIsDirty(document.forms["someForm"])) {
-
- if (e) {
- e.returnValue = "You have unsaved changes.";
- }
-
- return "You have unsaved changes.";
- }
- };
10 完全禁止使用后退键
下面的技巧放在页面中,则可以防止用户点后退键,这在一些情况下是需要的。代码如下:
- <SCRIPT type="text/javascript">
- window.history.forward();
- function noBack() { window.history.forward(); }
- </SCRIPT>
- </HEAD>
- <BODY onload="noBack();"
- onpageshow="if (event.persisted) noBack();" onunload="">
11 删除用户多选框中选择的项目
下面提供的技巧,是当用户在下拉框多选项目的时候,当点删除的时候,可以一次删除它们,代码如下:
- function selectBoxRemove(sourceID) {
-
- var src = document.getElementById(sourceID);
-
- for(var count= src.options.length-1; count >= 0; count--) {
-
- if(src.options[count].selected == true) {
- try {
- src.remove(count, null);
-
- } catch(error) {
-
- src.remove(count);
- }
- }
- }
- }
12 Listbox中的全选和非全选
如果对于指定的listbox,下面的方法可以根据用户的需要,传入true或false,分别代表是全选listbox中的所有项目还是非全选所有项目,代码如下:
- function listboxSelectDeselect(listID, isSelect) {
- var listbox = document.getElementById(listID);
- for(var count=0; count < listbox.options.length; count++) {
- listbox.options[count].selected = isSelect;
- }
- }
13 在Listbox中项目的上下移动
下面的代码,给出了在一个listbox中如何上下移动项目
- unction listbox_move(listID, direction) {
-
- var listbox = document.getElementById(listID);
- var selIndex = listbox.selectedIndex;
-
- if(-1 == selIndex) {
- alert("Please select an option to move.");
- return;
- }
-
- var increment = -1;
- if(direction == 'up')
- increment = -1;
- else
- increment = 1;
-
- if((selIndex + increment) < 0 ||
- (selIndex + increment) > (listbox.options.length-1)) {
- return;
- }
-
- var selValue = listbox.options[selIndex].value;
- var selText = listbox.options[selIndex].text;
- listbox.options[selIndex].value = listbox.options[selIndex + increment].value
- listbox.options[selIndex].text = listbox.options[selIndex + increment].text
-
- listbox.options[selIndex + increment].value = selValue;
- listbox.options[selIndex + increment].text = selText;
-
- listbox.selectedIndex = selIndex + increment;
- }
-
-
-
- listbox_move('countryList', 'up');
- listbox_move('countryList', 'down');
14 在两个不同的Listbox中移动项目
如果在两个不同的Listbox中,经常需要在左边的一个Listbox中移动项目到另外一个Listbox中去,下面是相关代码:
- function listbox_moveacross(sourceID, destID) {
- var src = document.getElementById(sourceID);
- var dest = document.getElementById(destID);
-
- for(var count=0; count < src.options.length; count++) {
-
- if(src.options[count].selected == true) {
- var option = src.options[count];
-
- var newOption = document.createElement("option");
- newOption.value = option.value;
- newOption.text = option.text;
- newOption.selected = true;
- try {
- dest.add(newOption, null);
- src.remove(count, null);
- }catch(error) {
- dest.add(newOption);
- src.remove(count);
- }
- count--;
- }
- }
- }
-
-
-
- listbox_moveacross('countryList', 'selectedCountryList');
15 快速初始化Javscript数组
下面的方法,给出了一种快速初始化Javscript数组的方法,代码如下:
- var numbers = [];
- for(var i=1; numbers.push(i++)<100;);
-
- 使用的是数组的push方法
16 截取指定位数的小数
如果要截取小数后的指定位数,可以使用toFixed方法,比如:
- var num = 2.443242342;
- alert(num.toFixed(2));
- 而使用toPrecision(x)则提供指定位数的精度,这里的x是全部的位数,如:
- num = 500.2349;
- result = num.toPrecision(4);
17 检查字符串中是否包含其他字符串
下面的代码中,可以实现检查某个字符串中是否包含其他字符串。代码如下:
- if (!Array.prototype.indexOf) {
- Array.prototype.indexOf = function(obj, start) {
- for (var i = (start || 0), j = this.length; i < j; i++) {
- if (this[i] === obj) { return i; }
- }
- return -1;
- }
- }
-
- if (!String.prototype.contains) {
- String.prototype.contains = function (arg) {
- return !!~this.indexOf(arg);
- };
- }
在上面的代码中重写了indexOf方法并定义了contains方法,使用的方法如下:
- var hay = "a quick brown fox jumps over lazy dog";
- var needle = "jumps";
- alert(hay.contains(needle));
18 去掉Javscript数组中的重复元素
下面的代码可以去掉Javascript数组中的重复元素,如下:
- function removeDuplicates(arr) {
- var temp = {};
- for (var i = 0; i < arr.length; i++)
- temp[arr[i]] = true;
-
- var r = [];
- for (var k in temp)
- r.push(k);
- return r;
- }
-
-
- var fruits = ['apple', 'orange', 'peach', 'apple', 'strawberry', 'orange'];
- var uniquefruits = removeDuplicates(fruits);
-
19 去掉String中的多余空格
下面的代码会为String增加一个trim()方法,代码如下:
- if (!String.prototype.trim) {
- String.prototype.trim=function() {
- return this.replace(/^\s+|\s+$/g, '');
- };
- }
-
-
- var str = " some string ";
- str.trim();
-
20 Javascript中的重定向
在Javascript中,可以实现重定向,方法如下:
- window.location.href = "http://viralpatel.net";
21 对URL进行编码
有的时候,需要对URL中的传递的进行编码,方法如下:
- var myOtherUrl =
- "http://example.com/index.html?url=" + encodeURIComponent(myUrl);
<html>
<head>
<script src="jquery.js" type="text/javascript"></script>
</head>
<body>
<input type="radio" name="riskLib" value="yjw1">杨军威1<br/>
<input type="radio" name="riskLib" value="yjw2">杨军威2<br/>
<input type="button" id="Btn_riskLib" />
<script type="text/javascript">
$(document).ready(function(){
$("#Btn_riskLib").bind("click",function(){
var id =$(":radio:checked").val();
if(id==null){
alert("请选择一个!");
}else {
alert(id);
}
})
});
</script>
</body>
</html>
任务和联系人是多对多关系,现在由联系人id查询出所有相关的任务
"SELECT t from Task t join t.contacters c where c.id = ?1"
比如:
一个老师教许多学生,一个学生被许多老师教,一个学生有好多书,同一种书被许多同学拥有.
要查询教拥有书"a"的学生的老师!
Hql语句:
SELECT t FROM Teacher t join t.students s join s.books b where b.name = 'a'
解释:t.students s中s并不是集合的意思,而是t的students对象的表别名,join t.students s这个hql,hibernate会翻译成两个表的内连接关系
错误写法:
SELECT t FROM teacher t where t.students.books.name = 'a'
其实道理是很显然的,t.students是一个Set,那么这个Set怎么可能有books这样的属性呢?同理books.name也不对,所以 使用表间连接并给出别名t.students s,此时的对象s才有books属性,所以可以写s.books b,最后使用b.name限制查询b.name = 'a'.
另外一种写法:
SELECT t FROM Teacher t,Student s,Book b where s.id in elements(t.students) and b.id in elements(s.books)
这种方法没有出错!不过这种方式要用子查询!
public Map readXml() {
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = dbf.newDocumentBuilder();
Document doc;
InputStream stream = this.getClass().getResourceAsStream("/dictionaries.xml");
doc = builder.parse(stream);
Element root = doc.getDocumentElement();
NodeList list = root.getElementsByTagName("dictionary");
Map map = new LinkedHashMap();
ArrayList<String> types = new ArrayList<String>();
for (int i = 0; i < list.getLength(); i++) {
String key = list.item(i).getAttributes().getNamedItem("name").getNodeValue();
String value = list.item(i).getAttributes().getNamedItem("value").getNodeValue();
map.put(key, value);
}
return map;
} catch (Exception ex) {
return null;
}
}
dictionaries.xml文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<dictionaries>
<dictionary name="项目类型" value="project.types" />
<dictionary name="项目状态" value="project.statuses" />
<dictionary name="任务阶段" value="task.stages" />
<dictionary name="任务状态" value="task.statuses" />
<dictionary name="发生几率" value="risk.probability" />
<dictionary name="危险程度" value="risk.harm" />
<dictionary name="风险状态" value="risk.status" />
<dictionary name="预案类别" value="risk.type" />
<dictionary name="合同类型" value="contract.type" />
<dictionary name="合同状态" value="contract.status" />
</dictionaries>
<html>
<body>
<input type="button" value="add row" id="addrow"/>
<table>
<tr>
<td width="20"><input type="checkbox" /><td>
<td>dddddddd</td>
</tr>
</table>
</body>
<script type="text/javascript" src="jquery-1.5.1.min.js"></script>
<script type="text/javascript" >
$(document).ready(function(){
$('input[type="checkbox"]').live('click',function(){//live给新添加的节点添加事件
$(this).parent().parent().remove();
});
$('addrow').mouseover(function(){
$(this).css('color','red');
});
$('addrow').mouseout(function(){
$(this).css('color','red');
});
$('#addrow').click(function(){
var tr = $('<tr>');
var td1 = $('<td>');
td1.attr('width','20');
var input = $('<input>');
input.attr('type','checkbox');
var td2 = $('<td>');
td2.text('aaaa');
td1.append(input);
tr.append(td1);
tr.append(td2);
//$('table').append(tr);
$('tbody tr:first').before(tr);
});
});
</script>
</html>
<html>
<body>
<input type="button" value="add row" id="addrow"/>
<table>
<tr>
<td width="20"><input type="checkbox" /><td>
<td>dddddddd</td>
</tr>
</table>
</body>
<script type="text/javascript" src="jquery-1.5.1.min.js"></script>
<script type="text/javascript" >
$(document).ready(function(){
$('input[type="checkbox"]').click(function(){
$(this).parent().parent().remove();
});
$('#addrow').click(function(){
var tr = $('<tr>');
var td1 = $('<td>');
td1.attr('width','20');
var input = $('<input>');
input.attr('type','checkbox');
var td2 = $('<td>');
td2.text('aaaa');
td1.append(input);
tr.append(td1);
tr.append(td2);
$('table').append(tr);
});
});
</script>
</html>
<html>
<head></head>
<body>
<form name="fm1" id="fm1">
name:<input type="text" name="name" id="name1" />
<input type="submit" id="s1"/>
</form>
<form name="fm2" id="fm2">
name:<input type="text" name="name" id="name2" />
<input type="submit" id="s2" />
</form>
<script type="text/javascript">
//var form = document.getElementById('fm2');
//var formarray = document.forms[1];//得到页面中所以表单的数组
//var form = document.forms['fm1'];//根据表单name属性得到数组
var form = document.fm1;//根据表单name属性得到数组
alert(form);
</script>
</body>
</html>
<html>
<head></head>
<body>
<input type="text" id="mytext" />
<span id="myspan"></span>
<script type="text/javascript">
var mytext=document.getElementById('mytext');
var myspan=document.getElementById('myspan');
mytext.onfocus = function(){
myspan.innerHTML = '得到焦点';
}
mytext.onblur = function(){
myspan.innerHTML = '失去焦点';
}
window.onbeforeunload=function(){
var v = mytext.value;
alert(v);
if(v){
return '444';
}
}
</script>
</body>
</html>
<html>
<head></head>
<body>
<div id="div1">1111111111
<div id="div2">2222222222</div>
</div>
<input type="button" id="btn" />
<a href="http://www.baidu.com" id="mya">163</a>
<a href="javascript:;" >普通按钮,不跳转</a>
<script type="text/javascript">
var eventUtil = {
addHandler:function(element,type,handler){
if(element.addEventListener){
element.addEventListener(type,handler,false);
}else if(element.attachEvent){
element.attachEvent('on'+type,handler);
}else {
element['on'+type]=handler;
}
},
getEvent:function(event){
return event ? event : window.event;
},
getElement: function(e){
if(e.target){
return e.target;
}else {
return e.srcElement;
}
},
preventDefault:function(e){
if(e.preventDefault){
e.preventDefault();
}else {
e.returnValue=false;
}
},
stopPropagation : function(e){
if(e.stopPropagation){
e.stopPropagation();
}else {
e.cancelBubble=true;
}
}
};
function test(event){
var e = eventUtil.getEvent(event);
alert("1="+e);
var element = eventUtil.getElement(e);
element.value = '33333333';
alert("2="+element);
}
var btn = document.getElementById('btn');
eventUtil.addHandler(btn,'click',test);
</script>
</body>
</html>
在非ie中
<html>
<head></head>
<body>
<div id="div1">1111111111
<div id="div2">2222222222</div>
</div>
<input type="button" id="btn" />
<a href="
http://www.baidu.com" id="mya">163</a>
<a href="javascript:;" >普通按钮,不跳转</a>
<script type="text/javascript">
document.getElementById('btn').onclick = function(event){
//在非ie中
alert(event.type);
alert(event.target);
}
document.getElementById('mya').onclick = function(event){
alert(event.cancelable);
if(event.cancelable){
event.preventDefault();//阻止事件的发生
}
}
document.getElementById('btn').onclick = function(event){
//alert(1);
event.stopPropagation();//阻止事件的传播
}
document.body.onclick=function(){
//alert(2);
}
</script>
</body>
</html>
在ie中
<html>
<head></head>
<body>
<div id="div1">1111111111
<div id="div2">2222222222</div>
</div>
<input type="button" id="btn" />
<a href="
http://www.baidu.com" id="mya">163</a>
<a href="javascript:;" >普通按钮,不跳转</a>
<script type="text/javascript">
var event;
function getEvent(){
event=window.event;
}
document.getElementById('btn').onclick = function(event){
getEvent();
alert(event.type);
alert(event.srcElement);//得到目标元素
event.cancelBubble = true;//取消事件冒泡
event.returnValue = false;//取消默认行为
}
//使用下面的方法可以在参数中得到event
document.getElementById('btn').attachEvent('onclick',function(event){
});
</script>
</body>
</html>
<html>
<head></head>
<body>
<div id="div1">1111111111
<div id="div2">2222222222</div>
</div>
<script type="text/javascript">
var EventUtil = {
addHandler:function(element,type,handler){
if(element.addEventListener){
element.addEventListener(type,handler,false);
}else if(element.attachEvent){
element.attachEvent('on'+type,handler);
}else {
element['on'+type]=handler;
}
},
removeHandler:function(element,type,handler){
if(element.addEventListener){
element.removeEventListener(type,handler,false);
}else if(element.attachEvent){
element.detachEvent('on'+type,handler);
}else {
element['on'+type]=null;
}
}
}
function alertid(){
alert(this.id);
}
var div1 = document.getElementById('div1');
var div2 = document.getElementById('div2');
EventUtil.addHandler(div2,'click',alertid);
//EventUtil.removeHandler(div2,'click',alertid);
//ie
//div1.attachEvent('onclick',alertid);
//div2.attachEvent('onclick',alertid);
//非ie
//div1.addEventListener('click',alertid,true);
//div2.addEventListener('click',alertid,true);
</script>
</body>
</html>
JavaScript 的事件是以一种流的形式存在的,一个事件会有多个元素同时响应。有时候这不是我们想要的,我们只需要某个特定的元素响应我们的绑定事件就可以了。
事件分类
捕获型事件(非IE)、冒泡型事件(所有浏览器都支持)
捕获型事件是自上而下的,而冒泡型事件是自下而上的。下面我用一个图来直观表示:
冒泡型事件我们在工作中可能会比较多遇到,但捕获型事件怎样才会执行到呢,如果我们想要在非 IE 浏览器中要创建捕获型事件,只需将 addEventListener 的第三个参数设为true就好了。
第三个参数false代表在冒泡时运行,true代表在捕获时运行。
ID为div1和div2的两个元素都被绑定了捕捉阶段的事件处理函数,这样:
当点击#div1(蓝色区域)时,应该会alert出”div1″ 当点击#div2(黄色区域)时,应该会先alert出”div1″,再alert出”div2″,因为在事件捕捉阶段,事件是从根元素向下传播的,#div1是#div2的父元素,自然绑定在#div1上的click事件也会先于#div2上的click事件被执行。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>冒泡事件</title> <script type="text/javascript"> var i = 1; function Add(sText,objText) { document.getElementById("Console").innerHTML +=sText + "执行顺序:" + i + "<br />" + "<hr />"; i = i + 1; //window.event.cancelBubble = true; } </script> </head> <body onclick="Add('body事件触发<br />','body')"> <div onclick="Add('div事件触发<br />','div')"> <p onclick="Add('p事件触发<br />','p')" style="background:#c00;">点击</p> </div> <div id="Console" style="border:solid 1px #ee0; background:#ffc;"></div> </body>
从这个例子我们可以很清楚的看到事件冒泡是从目标元素 P 一直上升到 body 元素。
例子:
<html>
<head></head>
<body>
<div id="div1">1111111111
<div id="div2">2222222222</div>
</div>
<script type="text/javascript">
function alertid(){
alert(0);
}
var div1 = document.getElementById('div1');
var div2 = document.getElementById('div2');
//ie
div1.attachEvent('onclick',alertid);
div2.attachEvent('onclick',alertid);
//非ie
//div1.addEventListener('click',alertid,true);
//div2.addEventListener('click',alertid,true);
</script>
</body>
</html>
在javascript操作css中,如果css的属性是比如background-color中间有横线的,在javascript操作是要遵守驼峰命名法,如mydiv.style.backgroundColor='blue';
在点击让图片显示和隐藏时css中style.visibility=’hidden’,让图片隐藏但是不释放空间,style.display=’none’,图片隐藏并且释放空间,style.display=’block’,图片显示,style.visibility=’visible’,图片显示。
一个定时不断改变颜色的例子:
<html>
<head>
<style type="text/css" >
#mydiv{
width:100px;
height:100px;
}
</style>
</head>
<body>
<div id="mydiv" ></div>
<input id="start" type="button" value="start" onclick="start()"/>
<input id="end" type="button" value="end" onclick="end()"/>
<script type="text/javascript">
var count = 4;
var now = 1;
function changea(){
var mydiv = document.getElementById('mydiv');
if(now==1){
mydiv.style.backgroundColor='blue';
}
if(now==2){
mydiv.style.backgroundColor='red';
}
if(now==3){
mydiv.style.backgroundColor='black';
}
if(now==4){
mydiv.style.backgroundColor='yellow';
}
now++;
// alert(now);
if(now>=5){
now=1;
}
var a =setTimeout(changea,1000);
}
changea();
</script>
</body>
</html>
package com.test.yjw;
public class Sort {
//冒泡
/**
*
*/
public static void bubbleSort(int a[]) {
int len = a.length;
for (int i = 0; i < len - 1; i++) {
for (int j = 0; j < len - 1 - i; j++) {
if (a[j] > a[j + 1]) {
int temp = a[j];
a[j] = a[j + 1];
a[j + 1] = temp;
}
}
}
for(int t : a){
System.out.println(t);
}
}
//选择排序
public static void selectSort(int a[]) {
int temp = 0;
int len = a.length;
for (int i = 0; i < len - 1; i++) {
int min = a[i];
int index = i;
for (int j = i + 1; j < len; j++) {
if (min > a[j]) {
min = a[j];
index = j;
}
}
temp = a[i];
a[i] = a[index];
a[index] = temp;
}
for(int t : a){
System.out.println(t);
}
}
// 插入排序{9,5,1,3,7,8,6,2,0,4}
public static void insertSort(int a[]) {
int len = a.length;
for (int i = 1; i < len; i++) {
int temp = a[i];// 待插入的值
int index = i;// 待插入的位置
while (index > 0 && a[index - 1] > temp) {
a[index] = a[index - 1];// 待插入的位置重新赋更大的值
index--;// 位置往前移
}
a[index] = temp;
}
for(int t : a){
System.out.println(t);
}
}
//快速排序
public static void quickSort(int a[], int low, int height) {
if (low < height) {
int result = partition(a, low, height);
quickSort(a, low, result - 1);
quickSort(a, result + 1, height);
}
}
public static int partition(int a[], int low, int height) {
int key = a[low];
while (low < height) {
while (low < height && a[height] >= key)
height--;
a[low] = a[height];
while (low < height && a[low] <= key)
low++;
a[height] = a[low];
}
a[low] = key;
return low;
}
public static void swap(int a[], int i, int j) { // 通过临时变量,交换数据
int tmp = a[i];
a[i] = a[j];
a[j] = tmp;
} // 第一次交换分析
public static void quicksort(int a[], int low, int high) { // 假设传入low=0; high=a.length-1;
if (low < high) { // 条件判断
int pivot, p_pos, i; // 声明变量
p_pos = low; // p_pos指向low,即位索引为0位置 ;
pivot = a[p_pos]; // 将0位置上的数值赋给pivot;
for (i = low + 1; i <= high; i++) { // 循环次数, i=1;
if (a[i]>pivot) { // 1位置的数与0位置数作比较: a[1]>a[0]
p_pos++; // 2位与1位比较,3位与2位比较......
swap(a, p_pos, i); // 传参并调用swap
}
}
swap(a, low, p_pos); // 将p_pos设为high再次调用swap
quicksort(a, low, p_pos - 1); // 递归调用,排序左半区
quicksort(a, p_pos + 1, high); // 递归调用,排序右半区
}
}
public static void main(String[] args) {
int[] a =new int[]{9,5,1,3,7,8,6,2,0,4};
//Sort.bubbleSort(a);
//Sort.selectSort(a);
//Sort.insertSort(a);
Sort.quickSort(a, 0, a.length-1);
for(int t : a){
System.out.println(t);
}
}
}
在java语言 I/O库的设计中,使用了两个结构模式,即装饰模式和适配器模式。
在任何一种计算机语言中,输入/输出都是一个很重要的部分。与一般的计算机语言相比,java将输入/输出的功能和使用范畴做了很大的扩充。因此输入输出在java语言中占有极为重要的位置。
java语言采用流的机制来实现输入/输出。所谓流,就是数据的有序排列,流可以是从某个源(称为流源,或者 Source of Stream)出来,到某个目的(Sink of Stream)地去。根据流的方向可以将流分成输出流和输入流。程序通过输入流读取数据,想输出流写出数据。
例如:一个java程序可以使用FileInputStream类从一个磁盘文件读取数据,如下图:
像FileInputStream这样的处理器叫流处理器。一个流处理器就像一个流的管道一样,从一个流源吸入某种类型的数据,并输出某种类型的数据。上面的示意图叫流的管道图。
类似地,也可以用FileOutputStream类向一个磁盘文件写数据,如下图:
在实际的应用当中,这样简单的机制并没有太大的用处。程序需要写出的往往是非常结构话的信息,因此这些Byte类型的数据实际上是一些数字、文字、源代码等。java的I/O库提供了一个称作链接(Chaining)的机制,可以将一个流处理器与另一个流处理器首尾相接,以其中之一的输出为输入,形成一个流管道的链接。
例如,DateInputStream流处理器可以把FileInputStream流对象的输出当做输入,将Byte类型的数据转换成java的原始数据类型和String数据类型,如下图:
类似地,向一个文件中写入Byte类型的数据也不是一个简单的过程。一个程序需要向一个文件里写入的数据往往是结构化的,而Byte类型则是原始的类型,因此,在写入的时候必须首先经过转换。DateOutputStream流处理器提供了接受原始数据类型和String数据类型的方法,而这个流处理器的输出数据则是Byte类型。换而言之,DateOutputStream可以将源数据转换成Byte类型的数据,在输出出来。
这样一来,就可以将DateOutputStream与FileOutputStream链接起来。这样做的结果就是,程序可以将原始数据类型和String数据类型的源数据写到这个链接好的双重管道里面,达到将结构话数据写到磁盘文件里的目的,如下图所示:
这是链接的威力。
流处理器所处理的流必定都有流源,如果将流类所处理的流源分类的话,那么基本可以分成两大类:
(1)数组、String、File等,这一种叫原始流源。
(2)同样类型的流用做链接流类的流源,就叫做链接流源。
java I/O库的设计原则
java语言的I/O库是对各种常见的流源、流汇以及处理过程的抽象化。客户端的java 程序不必知道最终的的流源、流汇是磁盘上的文件还是一个数组,或者是一个线程;也不比插手到诸如数据是否缓存、可否按照行号读取等处理的细节中去。
要理解java I/O 这个庞大而复杂的库,关键是掌握两个对称性和两个设计模式。
java I/O库的两个对称性
java I/O库具有两个对称性,它们分别是:
(1)输入-输出对称:比如InputStream 和OutputStream 各自占据Byte流的输入和输出的两个平行的等级结构的根部;而Reader和Writer各自占据Char流的输入和输出的两个平行的等级结构的根部。
(2)byte-char对称:InputStream和Reader的子类分别负责byte和插入流的输入;OutputStream和Writer的子类分别负责byte和Char流的输出,它们分别形成平行的等级结构。
java I/O库的两个设计模式
ava I/O库的总体设计是符合装饰模式和适配器模式的。如前所述,这个库中处理流的类叫流类。
装饰模式:在由InputStream、OutputStream、Reader和Writer代表的等级结构内部,有一些流处理器可以对另一些流处理器起到装饰作用,形成新的、具有改善了的功能的流处理器。
适配器模式:在由InputStream、OutputStream、Reader和Writer代表的等级结构内部,有一些流处理器是对其他类型的流处理器的适配。这就是适配器的应用。
装饰模式的应用
装饰模式在java中的最著名的应用莫过于java I/O标准库的设计了。
由于java I/O库需要很多性能的各种组合,如果这些性能都是用继承来实现,那么每一种组合都需要一个类,这样就会造成大量行重复的类出现。如果采用装饰模式,那么类的数目就会大大减少,性能的重复也可以减至最少。因此装饰模式是java I/O库基本模式。
装饰模式的引进,造成灵活性和复杂性的提高。因此在使用 java I/O 库时,必须理解java I/O库是由一些基本的原始流处理器和围绕它们的装饰流处理器所组成的。
InputStream类型中的装饰模式 InputStream有七个直接的具体子类,有四个属于FilterInputStream的具体子类,如下图所示:
上图中所有的类都叫做流处理器,这个图叫做(InputStream类型)流处理器图。根据输入流的源的类型,可以将这些流分为两种,即原始流类和链接流处理器。
原始流处理器
原始流处理器接收一个Byte数组对象、String对象、FileDescriptor对象或者不同类型的流源对象(就是前面所说的原始流源),并生成一个InputStream类型的流对象。在InputStream类型的流处理器中,原始流处理器包括以下四种:
(1)ByteArrayInputStream:为多线程的通讯提供缓冲区操作工作,接受一个Byte数组作为流的源。
(2)FileInputStream:建立一个与文件有关的输入流。接受一个File对象作为流的源。
(3)PipedInputStream:可以和PipedOutputStream配合使用,用于读入一个数据管道的数据。接受一个PipedOutputStream作为源。
(4)StringBufferInputStream:将一个字符串缓冲区抓换为一个输入流。接受一个String对象作为流的源。
与原始流处理器相对应的是链接流处理器。
链接流处理器
所谓链接流处理器就是可以接受另一个(同种类的)流对象(就是链接流源)作为流源,并对之进行功能扩展的类。InputStream类型的链接流处理器包括以下几种,它们接受另一个InputStream对象作为流源。
(1)FilterInputStream称为过滤输入流,它将另一个输入流作为流源。这个类的子类包括以下几种:
BufferInputStream:用来从硬盘将数据读入到一个内存缓冲区中,并从此缓冲区提供数据。
DateInputStream:提供基于多字节的读取方法,可以读取原始数据类型的数据。
LineNumberInputStream:提供带有行计算功能的过滤输入流。
PushbackInputStream: 提供特殊的功能,可以将已读取的直接“推回”输入流中。
(2)ObjectInputStream 可以将使用ObjectInputStream串行化的原始数据类型和对象重新并行化。
(3)SequenceInputStream可以将两个已有的输入流连接起来,形成一个输入流,从而将多个输入流排列构成一个输入流序列。
必须注意的是,虽然PipedInuptStream接受一个流对象PipedOutputStream作为流的源,但是PipedOutputStream流对象的类型不是InputStream,因此PipedInputStream流处理器仍属于原始流处理器。
抽象结构图
上面流处理器图与装饰模式的结构图有明显的相同之处。实际上InputStream类型的流处理器结构确实符合装饰模式,而这可以从它们在结构中所扮演的角色中分辩出来。
装饰模式的各个角色 在所有InputStream类型的链接流处理其中,使用频率最大的就是FilterInputStream类,以这个类为抽象装饰角色的装饰模式结构非常明显和典型。以这个类为核心说明装饰模式的各个角色是由哪些流处理器扮演:
抽象构件(Component)角色:由InputStream扮演。这是一个抽象类,为各种子类型处理器提供统一的接口。
具体构建(Concrete Component)角色:由ByteArrayInputStream、FileInputStream、PipedInputStream以及StringBufferInputStream等原始流处理器扮演。它们实现了抽象构建角色所规定的接口,可以被链接流处理器所装饰。
抽象装饰(Decorator)角色:由FilterInputStream扮演。它实现了InputStream所规定的接口。
具体装饰(Concrete Decorator)角色:由几个类扮演,分别是DateInputStream、BufferedInputStream 以及两个不常用到的类LineNumberInputStream和PushbackInputStream。
链接流其实就是装饰角色,原始流就是具体构建角色,如下图所示:
一方面,链接流对象接受一个(同类型的)原始流对象或者另一个(同类型的)链接流对象作为流源;另一方面,它们都对流源对象的内部工作方法做了相应的改变,这种改变是装饰模式所要达到的目的。比如:
(1)BufferedInputStream “装饰” 了InputStream的内部工作方式,使得流的读入操作使用缓冲机制。在使用了缓冲机制后,不会对每一次的流读入操作都产生一个物理的读盘动作,从而提高了程序的效率。在涉及到物理流的读入时,都应当使用这个装饰流类。
(2)LineNumberInputStream和PushbackInputStream也同样“装饰”了InputStream的内部工作方式,前者使得程序能够按照行号读入数据;后者能使程序在读入的过程中退后一个字符。后两个装饰类可能在实际的编程工作中很少用到,因为它们是为了支持用java语言做编译器而准备的。
(3)DateInputStream子类读入各种不同的原始数据类型以及String类型的数据,这一点可以从它提供的各种read()方法看出来:
readByte()、readUnsignedByte()、readShort()、readUnsignedShort()、readChar()、readInt()、readLong()、readFloat()、readDouble()、readUTF()。使用这个流处理器以及它的搭档DateOutputStream,可以将原始数据通过流从一个地方移到另一个地方。
OutputStream 类型中的装饰模式 outputStream是一个用于输出的抽象类,它的接口、子类的等级结构、子类的功能都和InputStream有很好的对称性。在OutputStream给出的接口里,将write换成read就得到了InputStream的接口,而其具体子类则在功能上面是平行的。
(1)针对byte数字流源的链接流类,以ByteArrayInputStream描述输入流,以ByteArrayOutputStream描述输出流。
(2)针对String流源的链接流类,以StringBufferInputStream描述输入流,以StringBufferOutputStream描述输出流。
(3)针对文件流源的链接流类,以FileInputStream描述输入流,以FileOutputStream描述输出流。
(4)针对数据管道流源的链接流类,以PipedInputStream描述输入流,以PipedOutputStream描述输出流。
(5)针对以多个流组成的序列,以SequenceInputStream描述输入流,以SequenceOutputStream描述输出流。
OutputStream类型有哪些子类
outputStream有5个直接的具体子类,加上三个属于FilterInputStream的具体子类,一共有8个具体子类,如下图:
原始流处理器
在OutputStream类型的流处理器中,原始流处理器包括以下三种:
ByteArrayOutputStream:为多线程的通信提供缓冲区操作功能。输出流的汇集是一个byte数组。
FileOutputStream:建立一个与文件有关的输出流。输出流的汇集是一个文件对象。
PipedOutputStream: 可以与PipedInputStream配合使用,用于向一个数据管道输出数据。
链接流处理器 OutputStream类型的链接流处理器包括以下几种:
(1)FilterOutputStream:称为过滤输出流,它将另一个输出流作为流汇。这个类的子类有如下几种:
BufferedOutputStream:用来向一个内存缓冲区中写数据,并将此缓冲区的数据输入到硬盘中。
DataOutputStream:提供基于多字节的写出方法,可以写出原始数据类型的数据。
PrintStream:用于产生格式化输出。System.out 静态对象就是一个
PrintStream。
(2)ObjectOutputStream 可以将原始数据类型和对象串行化。
装饰模式的各个角色
在所有的链接流处理器中,最常见的就是FilterOutputStream类。以这个类为核心的装饰模式结构非常明显和典型,如下图:
装饰模式所涉及的各个角色:
抽象构件(Component)角色:由OutputStream扮演,这是一个抽象类,为各种的子类型流处理器提供统一的接口。
具体构件(Concrete Component)角色:由ByteArrayOutputStream、FileOutputStream、PipedOutputStream等扮演,它们均实现了OutputStream所声明的接口。
抽象装饰(Decorator)角色:由FilterOutputStream扮演,它与OutputStream有相同的接口,而这正是装饰类的关键。
具体装饰(Concrete Decorator)角色:由几个类扮演,分别是BufferedOutputStream、DateOutputStream、以及PrintStream。
所谓链接流,就是装饰模式中的装饰角色,原始流就是具体构件角色。
与DateInputStream相对应的是DataOutputStream,后者负责将由原始数据类型和String对象组成的数据格式化,并输出到一个流中,使得任何机器上的任何DataInputStream类型的对象都可以读入这些数据。所有的方法都是以write开始。
如果需要对数据进行真正的格式化,以便输出到像控制台显示那样,那就需要使用PrintStream。
PrintStream可以对由原始数据类型和String对象组成的数据进行格式化,以形成可以阅读的格式;而DataOutputStream则不同,它将数据输出到一个流中,以便DataInputStream可以在任何机器而后操作系统中都可以重新将数据读入,并进行结构重建。
PrintStream对象最重要的两个方法是print() 和println(),这两个方法都是重载的,以便可以打印出所有使用类型的数据。这两个方法之间的区别是后者每行结束时多打印出一个换行符号。
BufferedOutputStream对一个输出流进行装饰,使得流的写出操作使用缓冲机制。在使用缓冲机制后,不会对每一次的流的写入操作都产生一个物理的写动作,从而提高的程序的效率。在涉及到物理流的地方,比如控制台I/O、文件I/O等,都应当使用这个装饰流处理器。
Reader类型中的装饰模式 在Reader类型的流处理器中,
原始流处理器包括以下四种:
(1)CharArrayReader:为多线程的通信提供缓冲区操作功能。
(2)InputStreamReader:这个类有一个子类--FileReader。
(3)PipedReader:可以与PipedOutputStream配合使用,用于读入一个数据管道的数据。
(4)StringReader:建立一个与文件有关的输入流。
链接流处理器包括以下:
(1)BufferedReader:用来从硬盘将数据读入到一个内存缓冲区,并从此缓冲区提供数据,这个类的子类为
LineNumberReader。
(2)FilterReader:成为过滤输入流,它将另一个输入流作为流的来源。这个类的子类有PushbackReader,提供基于多字节的读取方法,可以读取原始数据类型的数据,Reader类型的类图如下所示:
Reader类型中,装饰模式所涉及的各个角色:
(1)抽象构建(Component)角色:有Reader扮演。这是一个抽象类,为各种的子类型流处理器提供统一的接口。
(2)具体构建(Concrete Component)角色:由CharArrayReader、InputStreamReader、PiPedReader、StringReader等扮演,他们均实现了Reader所声明的接口。
(3)抽象装饰(Decorator)角色:由BufferedReader和FilterReader扮演。这两者有着与Reader相同的接口,它们分别给出两个装饰角色的等级结构,第一个给出LineNumberReader作为具体装饰角色,另一个给出PushbackReader 作为具体装饰角色。
(4)具体装饰(Concrete Decorator)角色:LineNumberReader作为BufferedReader的具体装饰角色,BufferedReader作为FilterReader的具体装饰角色。
如下图所示,标有聚合连线的就是抽象装饰角色:
Writer类型中的装饰模式 Writer类型是一个与Reader类型平行的等级结构,而且Writer类型的等级结构几乎与Reader的等级结构关于输入/输出是对称的。如图所示:
在Writer类型的流处理器中,原始流处理器包括以下四种:
(1)CharArrayWriter:为多线程的通信提供缓冲区的操作功能。
(2)OutputStreamWriter:建立一个与文件有关的输出流。含有一个具体子类FileWrite,为Write类型的输出流提供文件输出功能。
(3)PipedWriter:可以和PipedOutputStream配合使用,用于读如果一个数据管道的数据。
(4)StringWriter:想一个StringBuffer写出数据。
链接流处理器包括以下三种:
(1)BufferedWriter:为Writer类型的流处理器提供缓冲区功能。
(2)FilterWriter:称为过滤输入流,它将另一个输入流作为流的来源。这是一个没有子类的抽象类。
(3)PrintWriter:支持格式化的文字输出。
Writer类型中,装饰模式所涉及的各个角色:
(1)抽象构建(Component)角色:由Write扮演。这是一个抽象类,为为各种子类型的流处理器提供统一的接口。
(2)具体构建(Concrete Component):角色由
CharArrayWriter、OutputStreamWriter、
PipedWriter、StringWriter扮演,它们实现了Writer所声明的接口。 (3)抽象装饰(Decorator)角色:由
BufferedWriter、FilterWriter、PrintWriter扮演,它们有着与Write
相同的接口。
(4)具体装饰(Concrete Decorator)角色:与抽象装饰角色合并。
如下图所示,标出了从抽象装饰角色到抽象构件角色的聚合连线,更易于与装饰模式的结构图比较。
适配器模式的应用
适配器模式是java I/O库中第二个最重要的设计模式。
InputStream原始流处理器中的适配器模式 InputStream类型的原始流处理器是适配器模式的应用。
ByteArrayInputStream是一个适配器类
ByteArrayInputStream继承了InputStream的接口,而封装了一个byte数组。换而言之,它将一个byte数组的接口适配成了InputStream流处理器的接口。
java语言支持四种类型:java类、java接口、java数组和原始类型。前三章是引用类型,类和数组的实例都是对象,原始类型的值不少对象。java语言的数组是像所有其他对象一样的对象,而不管数组中所存放的元素的类型是什么。这样一来,ByteArrayInputStream就符合适配器模式的描述,而且是一个对象形式的适配器类。如下图所示:
StringBufferInputStream是一个适配器类
StringBufferInputStream继承了InputStream类型,同时持有一个对String类型的引用。这是将String对象适配成InputStream类型的对象形式的适配器模式,如下图:
OutputStream原始流处理器中的适配器模式
在OutputStream类型中,所有的原始流处理器都是适配器类。
ByteArrayOutputStream是一个适配器类
ByteArrayOutputStream继承了OutputStream类型,同事持有一个对byte数组的引用。它把一个byte数组的接口适配成OutputStream类型的接口,因此也是一个对象类型的适配器模式的应用。如下图:
FileOutputStream是一个适配器类
FileOutputStream继承OutputStream,同时持有一个对FileDescriptor对象的引用。这是一个将FileDescriptor适配成OutputStream接口的对象形式的适配器模式,如下图所示:
PipedOutputStream是一个适配器类
PipedOutputStream总是和PipedInputStream一起使用,它接收一个类型为PipedInputStream的输入类型,并将之转换成OutputStream类型的输出流,这是一个对象形式的适配器模式应用。如下图:
Reader原始流处理器中的适配器模式
Reader 类型的原始流处理器都是适配器模式的应用。
CharArrayReader是一个适配器类。
CharArrayReader将一个Char数组适配成Reader类型的输入流,因此它是一个对象形式的适配器应用,如下图所示:
StringReader是一个适配器类
StringReader 继承了Reader类型,持有一个对String类型的引用。它将String的接口适配成Reader类型的接口,如下图所示:
Writer类型中的适配器模式
Writer类型中的原始流处理器就是适配器模式的具体应用。
CharArrayWriter是一个适配器类。
CharArrayWriter将一个Char数组适配成Writer 接口,如下图所示:
PipedWriter是一个适配器类
PipedWriter总是与PiPedReader一同使用,它将一个PipedReader对象的接口适配成一个Writer类型的接口,如下图所示:
StringWriter是一个适配器类
StringWriter继承Writer类型,同时持有一个StringBuffer对象,它将StringBuffer对象的接口适配成为了
Writer类型的接口,是一个对象形式的适配器 模式的应用,如下图所示:
从byte流到char流的适配
在java语言的标准库 java I/O 里面,有一个InputStreamReader类叫做桥梁(bridge)类。InputStreamReader是从byte流到char流的一个桥梁,它读入byte数据并根据指定的编码将之翻译成char数据。
InputStreamReader虽然叫“桥梁”,但它不爽桥梁模式,是适配器模式的应用。
InputStreamReader
InputStreamReader是从byte输入流到char输入流的一个适配器。下图所示就是InputStreamReader 的结构图:
为了说明适配器类InputStreamReader是如何使用,请看下面例子。Echo类可以将控制台输入的任何字符串从新打印出来,源代码如下:
Echo.java
01 |
package com.think.cla; |
03 |
import java.io.BufferedReader; |
04 |
import java.io.IOException; |
05 |
import java.io.InputStreamReader; |
09 |
public static void main(String [] args) throws IOException{ |
11 |
InputStreamReader input = new InputStreamReader(System.in); |
12 |
System.out.println( "Enter data and push enter:" ); |
13 |
BufferedReader reader = new BufferedReader(input); |
14 |
line = reader.readLine(); |
15 |
System.out.println( "Data entered :" +line); |
可以看出,这个类接受一个类型为inputStream的System.in对象,将之适配成Reader类型,然后再使用
BufferedReader类“装饰”它,将缓冲功能加上去。这样一来,就可以使用BufferedReader对象的readerLine()
方法读入整行的输入数据,数据类型是String。
在得到这个数据之后,程序又将它写出到System.out 中去,完成了全部的流操作,下图所示为其管道图:
本系统使用了BufferedReader来为流的读入提供缓冲功能,这样做的直接效果是可以使用readLine()方法按行读入数据。但是由于Reader接口并不提供readLine()方法,所以这样一来,系统就必须声明一个BufferedReader类型的流处理器,而不是一个Reader类型的流处理器,这意味着装饰模式的退化。
在上面的管道连接过程中,InputStreamReader 起到了适配器的作用,它将一个byte类型的输入流适配成为一个char类型的输入流。在这之后,BufferedReader则起到了装饰模式的作用,将缓冲机制引入到流的读入中。因此这个例子涉及到了两个设计模式。
package com.scpii.ent.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import com.scpii.ent.mode.bean.DataSet;
public class ExcelOperClass {
private static String EXCEL_2003 = ".xls";
private static String EXCEL_2007 = ".xlsx";
public static void readExcelJXL() {
}
/**
* 通过POI方式读取Excel
*
* @param excelFile
*/
public static DataSet readExcelPOI(String filePath, Integer cons) throws Exception {
File excelFile = new File(filePath);
if (excelFile != null) {
String fileName = excelFile.getName();
fileName = fileName.toLowerCase();
if (fileName.toLowerCase().endsWith(EXCEL_2003)) {
DataSet dataSet = readExcelPOI2003(excelFile, cons);
return dataSet;
}
if (fileName.toLowerCase().endsWith(EXCEL_2007)) {
DataSet dataSet = readExcelPOI2007(excelFile, cons);
return dataSet;
}
}
return null;
}
/**
* 读取Excel2003的表单
*
* @param excelFile
* @return
* @throws Exception
*/
private static DataSet readExcelPOI2003(File excelFile, Integer rCons)
throws Exception {
List<String[]> datasList = new ArrayList<String[]>();
Set<String> colsSet = new HashSet<String>();
InputStream input = new FileInputStream(excelFile);
HSSFWorkbook workBook = new HSSFWorkbook(input);
// 获取Excel的sheet数量
Integer sheetNum = workBook.getNumberOfSheets();
// 循环Sheet表单
for (int i = 0; i < sheetNum; i++) {
HSSFSheet sheet = workBook.getSheetAt(i);
if (sheet == null) {
continue;
}
// 获取Sheet里面的Row数量
Integer rowNum = sheet.getLastRowNum() + 1;
for (int j = 0; j < rowNum; j++) {
if (j>rCons) {
System.out.println("===========");
HSSFRow row = sheet.getRow(j);
if (row == null) {
continue;
}
Integer cellNum = row.getLastCellNum() + 1;
String[] datas = new String[cellNum];
for (int k = 0; k < cellNum; k++) {
HSSFCell cell = row.getCell(k);
if (cell == null) {
continue;
}
if (cell != null) {
cell.setCellType(HSSFCell.CELL_TYPE_STRING);
String cellValue = "";
int cellValueType = cell.getCellType();
if (cellValueType == cell.CELL_TYPE_STRING) {
cellValue = cell.getStringCellValue();
}
if (cellValueType == cell.CELL_TYPE_NUMERIC) {
Double number = cell.getNumericCellValue();
System.out.println("字符串+++=========="+number.intValue());
cellValue = cell.getNumericCellValue() + "";
}
if (rCons==k) {
colsSet.add(cellValue);
}
System.out.println(cellValue);
datas[k] = cellValue;
}
}
datasList.add(datas);
}
}
}
DataSet dataSet = new DataSet(null, null, datasList, colsSet);
return dataSet;
}
/**
* 读取Excel2007的表单
*
* @param excelFile
* @return
* @throws Exception
*/
private static DataSet readExcelPOI2007(File excelFile, Integer rCons) throws Exception {
List<String[]> datasList = new ArrayList<String[]>();
Set<String> cosSet = new HashSet<String>();
InputStream input = new FileInputStream(excelFile);
XSSFWorkbook workBook = new XSSFWorkbook(input);
// 获取Sheet数量
Integer sheetNum = workBook.getNumberOfSheets();
for (int i = 0; i < sheetNum; i++) {
XSSFSheet sheet = workBook.getSheetAt(i);
if (sheet == null) {
continue;
}
// 获取行值
Integer rowNum = sheet.getLastRowNum() + 1;
for (int j = 0; j < rowNum; j++) {
if (j > rCons) {
System.out.println("=============");
XSSFRow row = sheet.getRow(j);
if (row == null) {
continue;
}
Integer cellNum = row.getLastCellNum() + 1;
String[] datas = new String[cellNum];
for (int k = 0; k < cellNum; k++) {
XSSFCell cell = row.getCell(k);
if (cell==null) {
continue;
}
if (cell != null) {
cell.setCellType(XSSFCell.CELL_TYPE_STRING);
String cellValue = "";
int cellValueType = cell.getCellType();
if (cellValueType == cell.CELL_TYPE_STRING) {
cellValue = cell.getStringCellValue();
}
if (cellValueType == cell.CELL_TYPE_NUMERIC) {
Double number = cell.getNumericCellValue();
System.out.println("字符串+++=========="+number.toString());
cellValue = cell.getNumericCellValue() + "";
}
System.out.println(cellValue);
if (rCons == k) {
cosSet.add(cellValue);
}
datas[k] = cellValue;
}
}
datasList.add(datas);
}
}
}
DataSet dataSet = new DataSet(null, null, datasList,cosSet);
return dataSet;
}
public static void main(String[] args) {
// try {
// DataSet dataSet = readExcelPOI("D:\\部门员工资料.xls", 0);
// System.out.println("================================");
// Set<String> datas = dataSet.getConStrctSet();
// String[] datastr = new String[datas.size()];
// datastr = datas.toArray(datastr);
// for (int i = 0; i < datastr.length; i++) {
// System.out.println(datastr[i]);
// }
// } catch (Exception e) {
// e.printStackTrace();
// }
System.out.println(52%4);
}
}
package com.scpii.ent.mode.bean;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
public class DataSet {
private String[] headers;
private String[] rowHeaders;
private List<String[]> datasList = new ArrayList<String[]>();
private Set<String> conStrctSet;
public DataSet(String[] headers, String[] rowHeaders,
List<String[]> datasList, Set<String> conStrctSet) {
this.headers = headers;
this.rowHeaders = rowHeaders;
this.datasList = datasList;
this.conStrctSet = conStrctSet;
}
public DataSet(String[] header, String[] rowsHeader,
List<String[]> datasList2) {
this.headers = header;
this.rowHeaders = rowsHeader;
this.datasList = datasList2;
}
public String[] getHeaders() {
return headers;
}
public void setHeaders(String[] headers) {
this.headers = headers;
}
public String[] getRowHeaders() {
return rowHeaders;
}
public void setRowHeaders(String[] rowHeaders) {
this.rowHeaders = rowHeaders;
}
public List<String[]> getDatasList() {
return datasList;
}
public void setDatasList(List<String[]> datasList) {
this.datasList = datasList;
}
public Set<String> getConStrctSet() {
return conStrctSet;
}
public void setConStrctSet(Set<String> conStrctSet) {
this.conStrctSet = conStrctSet;
}
}
Jquery框架为jquery对象定义了独立使用的方法和属性,它无法直接调用dom对象的方法,dom对象也无法直接调用jquery对象的方法和属性。
Jquery对象和dom对象是可以相互转换的,因为他们所操作的对象都是dom元素,只不过jquery对象包含了多个dom元素,而dom对象本身就是一个dom元素,简单地说,jquery对象是dom元素的数组,称为类数组,而dom对象就是单个的dom元素。
1.把jquery对象转换成dom对象
(1)借助数组下标来读取jquery对象集合中的某个dom元素对象。
Var $li = $(‘li’);//jquery对象
Var li = $li[0];//dom对象
(2)借助jquery对象的get()方法
Var $li = $(‘li’);//jquery对象
Var li = $li.get(0);//dom对象
2.dom对象转换为jquery对象
Var li = document.getElementsByTagName(‘div’);
Var $li = $(li[o]);//把第一个div元素封装为jquery对象
Var li = document.getElementsByTagName(‘div’);
Var $li = $(li);//把所以的div元素封装为jquery对象
Load事件必须等到网页中所以内容全部加载完毕后才执行。
当网页中内容很多时,load事件就会延迟
Jquery的ready事件是在dom结构绘制完毕后就执行,也就是说它在外部文件加载之前就执行了,ready事件先于load事件。
Load事件只能被编写一次,但是ready事件可以在同一个文档中多次定义。
<html>
<head>
</head>
<body>
<div class="panel"/>wlecome</div>
<script type="text/javascript" src="jquery-1.5.1.min.js"></script>
<script type="text/javascript">
$(document).ready(function(){
$('<input type="button" value="click me" /><input type="button" value="triggle click me" /><input type="button" value="detach handler" /><input type="button" value="show/hide text" />').appendTo($('body'));
$('input[type="button"]')
.eq(0).click(function(){
$(this).val("红色").addClass('red'); }).end().eq(1).click(function(){
alert(1);
}).end().eq(2).click(function(){
alert(2);
}).end().eq(3).toggle(function(){
$('.panel').hide('slow');
},function(){
$('.panel').show('slow');
}
);
});
</script>
</body>
<html/>
<tbody>
<tr>
<td width="20"><input type="checkbox" /></td>
<td>第二行</td>
</tr>
</tbody>
创建tbody中的内容
var tr = document.createElement('tr');
var ck_td = document.createElement('td');
var txt_td = document.createElement('td');
var ck = document.createElement('input');
var todo = document.createTextNode('第二行');
ck_td.setAttribute('width','20');
ck.setAttribute('type','checkbox');
ck_td.appendChild(ck);
txt_td.appendChild(todo);
tr.appendChild(ck_td);
tr.appendChild(txt_td);
document.getElementsByTagName('tbody')[0].appendChild(tr);
其他方法
tr.parentNode;//得到tr的父节点
tr.removeChild(td);//删除tr节点的子节点td
tr.nextElementSibling;//tr的下一个同级元素
tr.nextSibling;//tr的下一个同级元素//
<html>
<head>
</head>
<body>
<script type="text/javascript">
//继承之对象冒充方式,可以继承多个父类
function user(name){
this.name = name;
this.sayname = function(){
alert(this.name);
}
}
function student(name,score){
//user(name);
this.temp = user;
this.temp(name);
delete this.temp;
this.score = score;
this.sayscore = function(){
alert(this.score);
}
}
var s = new student('tom',33);
//s.sayname();
//s.sayscore();
//用call()函数实现继承
function user(name){
this.name = name;
this.sayname = function(){
alert(this.name);
}
}
function student(name,score){
user.call(this,name);
this.score = score;
this.sayscore = function(){
alert(this.score);
}
}
var s = new student('tom',33);
//s.sayname();
//s.sayscore();
//用apply()函数实现继承
function user(name){
this.name = name;
this.sayname = function(){
alert(this.name);
}
}
function student(name,score){
user.apply(this,[name]);
this.score = score;
this.sayscore = function(){
alert(this.score);
}
}
var s = new student('tom',33);
//s.sayname();
//s.sayscore();
//原型链方式实现继承
//1.将父类中所用通过prototype设置的属性或方法放到子类中
//2.并覆盖子类中所以的prototype的设置
//3.所以子类自己的所以的prototype的设置要放在继承父类的下面
//4.缺点是不支持多个继承,构造函数不能有参数
function user(){}
user.prototype.name = '';
user.prototype.say = function(){
alert(this.name);
}
function student(){}
student.prototype =new user();
student.prototype.age = 0;
student.prototype.show = function(){
alert(this.age);
}
var s = new student();
s.name = 'tom';
s.age = 44;
//s.say();
//s.show();
//alert(s instanceof user);
//alert(s instanceof student);
//混合模式实现继承
function user(name){
this.name = name;
}
user.prototype.sayname = function(){
alert(this.name);
}
function student(name){
user.call(this.name);
}
//将user中所有通过prototype设置的方法放到student中
student.prototype = new user();
student.prototype.age = 0;
student.prototype.sayage = function(){
alert(this.age);
}
var s = new student();
s.name = 'tom';
s.age = 44;
s.sayname();
s.sayage();
alert(s instanceof user);
alert(s instanceof student);
</script>
</body>
<html/>
function stringbuffer(){
this.array = new Array();
}
stringbuffer.prototype.append = function(s){
this.array.push(s);
}
stringbuffer.prototype.tostring = function(){
return this.array.join('-');
}
var sb = new stringbuffer();
sb.append('tom');
sb.append('lily');
alert( sb.tostring());
<html>
<head>
</head>
<body>
<script type="text/javascript">
//工厂模式创建对象,缺点是不能知道对象的类型
function createUser(name,age){
var o = {};
o.name=name;
o.age=age;
o.say=function(){
alert(this.name);
}
return o;
}
//user1 = createUser("tom",11);
//alert(user1.name);
//user2 = createUser("tom1",111);
//user2.say();
//构造函数创建对象。缺点是对象中的方法需要写在构造函数外面,有可能写很多方法
function user(name,age){
this.name=name;
this.age = age;
this.say = say;
}
function say(){
alert(this.name);
}
//var user1 = new user("tom",44);
//var user2 = new user("lily",66);
//alert(user1.name);
//user2.say();
//alert(user1 instanceof user);
//原型模式,缺点是不能有构造函数
function user(){}
user.prototype.name='';
user.prototype.age = 0;
user.prototype.address = [];
user.prototype.say = function(){
alert(this.name);
}
var user1 = new user();
user1.name = 'tom';
user1.age = 11;
user1.address = [1,2];
//user1.address.push("1","2");
var user2 = new user();
user2.name = 'lily';
user2.age = 22;
user2.address = [3,4];
//user2.address.push("3","4");
//alert(user1.name);
//alert(user1.age);
//alert(user1.address);
//user1.say();
//alert(user2.name);
//alert(user2.age);
//alert(user2.address);
//user2.say();
//构造函数+原型模式,构造方法构造属性,原型模式构造方法
function user(name,age){
this.name = name;
this.age = age;
this.address = ['1','2'];
}
user.prototype.say = function(){
alert(this.name);
}
var user1 = new user('tom',11);
var user2 = new user('lily',22);
user1.address.push('a','b');
user2.address = ['cc','dd'];
alert(user1.address);
alert(user2.address);
//动态原型模式
function user(name,age){
this.name = name;
this.age = age;
this.address = ['1','2'];
if(typeof this.say != 'function'){
user.prototype.say = function(){
alert(this.name);
}
}
}
var user1 = new user('tom',11);
var user2 = new user('lily',22);
alert(user1.say==user2.say);
</script>
</body>
<html/>
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'car.jsp' starting page</title>
</head>
<body>
<select id="car" onchange="sendAjax()">
<option>-- 请选择汽车品牌 --</option>
<option value="bmw">宝马</option>
<option value="audi">奥迪</option>
<option value="benz">奔驰</option>
</select>
<select id="type" onchange="sendType()">
<option>-- 请选择系列 --</option>
</select>
<script type="text/javascript">
var xmlHttp;
/*创建XMLHttpRequest对象*/
function createXMLHttpRequest() {
if(window.ActiveXObject) {
//IE
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
} else {
//chrome firefox opera
xmlHttp = new XMLHttpRequest();
}
}
function sendAjax(){
createXMLHttpRequest();
var name = document.getElementById("car").value;
xmlHttp.onreadystatechange = callback;//回调函数
xmlHttp.open("GET","car.jspx?name="+name,true);
xmlHttp.send();
}
function callback() {
if(xmlHttp.readyState == 4) {
if(xmlHttp.status == 200) {
var xml = xmlHttp.responseXML;
var types = xml.getElementsByTagName("recode");
document.getElementById("type").options.length = 1;
for(var i = 0;i < types.length;i++) {
//alert(types[i].childNodes[0].nodeValue);
var myOption = new Option(types[i].childNodes[0].nodeValue,types[i].childNodes[0].nodeValue);
document.getElementById("type").options.add(myOption);
}
} else {
alert("Ajax Error1!");
}
}
}
function sendType(){
createXMLHttpRequest();
var name = document.getElementById("type").value;
xmlHttp.onreadystatechange = callback2;//回调函数
xmlHttp.open("GET","ajax.jspx?name="+name,true);
xmlHttp.send();
}
function callback2() {
if(xmlHttp.readyState == 4) {
if(xmlHttp.status == 200) {
var result = xmlHttp.responseText;
alert(result);
}
} else {
alert("Ajax Error2!");
}
}
</script>
</body>
</html>
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class CarServlet extends HttpServlet {
/**
*
*/
private static final long serialVersionUID = 1L;
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//DB取出数据
Map<String, List<String>> data = new HashMap<String, List<String>>();
List<String> bmwList = new ArrayList<String>();
bmwList.add("521");
bmwList.add("621");
bmwList.add("721");
bmwList.add("821");
bmwList.add("X6");
List<String> audiList = new ArrayList<String>();
audiList.add("A1");
audiList.add("A2");
audiList.add("A3");
audiList.add("A4");
audiList.add("A5");
audiList.add("A6");
audiList.add("A8");
List<String> benzList = new ArrayList<String>();
benzList.add("B1");
benzList.add("B2");
benzList.add("B3");
benzList.add("B4");
benzList.add("B5");
data.put("bmw", bmwList);
data.put("audi", audiList);
data.put("benz", benzList);
//----------------------------------------------------------
String name = request.getParameter("name");
List<String> dataList = data.get(name);
response.setContentType("text/xml;charset=UTF-8");
PrintWriter out = response.getWriter();
out.print("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
out.print("<data>");
for(String str : dataList) {
out.print("<recode>"+str+"</recode>");
}
out.print("</data>");
out.flush();
out.close();
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet( request, response);
}
}
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class AjaxServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("method:" + request.getMethod());
String name = request.getParameter("name");
System.out.println("Hello! " + name);
response.setContentType("text/html");
PrintWriter out = response.getWriter();
/* if("tom".equals(name)) {
out.print("error");
} else {
out.print("ok");
}*/
out.print(name);
out.flush();
out.close();
}
}
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'index.jsp' starting page</title>
</head>
<body>
<input type="text" id="name" onblur="sendAjax()"/>
<img src="img/ajax.gif" style="display:none" id="loading"/>
<span id="result"></span>
<br/>
<!--
<input type="button" value="Send Ajax" onclick="sendAjax()"/>
-->
<script type="text/javascript">
var xmlHttp;
/*创建XMLHttpRequest对象*/
function createXMLHttpRequest() {
if(window.ActiveXObject) {
//IE
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
} else {
//chrome firefox opera
xmlHttp = new XMLHttpRequest();
}
}
function sendAjax(){
createXMLHttpRequest();
var name = document.getElementById("name").value;
//post
xmlHttp.open("POST", "ajax.jspx", true);
xmlHttp.onreadystatechange = callback;
xmlHttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xmlHttp.send("name="+name);
//get
//xmlHttp.open("GET","ajax.jspx?name="+name,true);
//xmlHttp.onreadystatechange = callback;
//xmlHttp.send();
}
function callback() {
if(xmlHttp.readyState == 4) {//服务器响应返回
document.getElementById("loading").style.display = "none";
if(xmlHttp.status == 200) {//响应正确
var result = xmlHttp.responseText;
if(result == "ok") {
document.getElementById("result").innerHTML = "√";
} else {
document.getElementById("result").innerHTML = "用户名已占用";
}
} else {
alert("Ajax Error!");
}
} else {
//进度条
document.getElementById("loading").style.display = "inline";
}
}
</script>
</body>
</html>
<html>
<head>
<script type="text/javascript">
var user = {name:'tom',age:'22'};
alert(user.name);
alert(user["name"]);
delete user.name;//删除属性
alert("name" in user);//判断属性是否在对象中
</script>
</head>
</html>
<html>
<head>
<script type="text/javascript">
function save(n1,n2){
function fn(){
return n1+n2;
}
return fn();
}
alert(save(2,3));
//闭包第一种
function test(){
var num = 10;
function inner(){
alert(num);
}
inner();
}
//test();
//闭包第二种
function add(n1,n2){
return function(){
return n1+n2;
}
}
//alert(add(2,3)());
</script>
</head>
</html>
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class JdbcTest {
public static void main(String[] args) throws ClassNotFoundException,SQLException {
//1.加载数据库驱动(提供一个jdbc的数据库驱动的名称)
Class.forName("com.mysql.jdbc.Driver");
//2.获取数据库连接
String url = "jdbc:mysql:///gooddb";
Connection conn = DriverManager.getConnection(url, "root", "root");
//3.获取Statment对象(该对象用于对数据库进行CRUD操作)
Statement stat = conn.createStatement();
//4.执行SQL语句
//String sql = "INSERT INTO t_class(classname) VALUES('java07')";
String sql = "UPDATE t_class SET classname = 'sql01' WHERE id = 2";
//executeUpdate()方法用于执行insert、update、delete语句,该方法返回影响数据库的行数
int rows = stat.executeUpdate(sql);
if(rows > 0) {
System.out.println("操作成功!");
}
//5.释放连接
stat.close();
conn.close();
}
}
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class SelectTest {
public static void main(String[] args) {
Connection conn = null;
Statement stat = null;
ResultSet rs = null;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql:///gooddb","root","root");
stat = conn.createStatement();
String sql = "select id,classname from t_class";
//获取结果集对象
rs = stat.executeQuery(sql);
while(rs.next()) {
//int id = rs.getInt("id");
int id = rs.getInt(1);
//String name = rs.getString("classname");
String name = rs.getString(2);
System.out.println("id:" + id + "\tclassname:" + name);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
//释放连接
try {
if(rs != null) {
rs.close();
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if(stat != null) {
stat.close();
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if(conn != null) {
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
}
package com.tCalendar.d;
/*
* java.util.Calendar 类学习
*/
import java.text.SimpleDateFormat;
/**
*
* @author Icer
*/
public class TCalendar {
private static SimpleDateFormat sDateFormat = new SimpleDateFormat("yyyyMMdd");
private String dayInfo[][];
private int dayCount;//间隔天数
public static void main(String[] args) {
String startDate = "20120101";
String endDate = "20120102";
TCalendar tCalendar = new TCalendar();
tCalendar.initDayInfo(startDate, endDate);
System.out.println("天数: " + tCalendar.getDayCount());
}
public void initDayInfo(String start,String end)
{
//初始化日期信息
java.util.Calendar cal1=java.util.Calendar.getInstance();
java.util.Calendar cal2=java.util.Calendar.getInstance();
java.util.Calendar cal3=java.util.Calendar.getInstance();
int year,month,day;
int i=0;
year=Integer.parseInt(start.substring(0,4));
month=Integer.parseInt(start.substring(4,6));
day=Integer.parseInt(start.substring(6,8));
cal1.set(year, month-1, day);
cal3.set(year, month-1, day);
year=Integer.parseInt(end.substring(0,4));
month=Integer.parseInt(end.substring(4,6));
day=Integer.parseInt(end.substring(6,8));
cal2.set(year, month-1, day);
while(!cal2.before(cal3))
{
i++;
cal3.add(java.util.Calendar.DAY_OF_MONTH, 1);//日期时间+1
}
//每日数据列表
dayInfo=new String[i+1][3];
i=0;
while(!cal2.before(cal1))
{
System.out.println("==" + cal1.getTime());
dayInfo[i][0]=sDateFormat.format(cal1.getTime());
i++;
cal1.add(java.util.Calendar.DAY_OF_MONTH, 1);
}
this.dayCount=i;
for (int j=0;j<i;j++)
{
this.dayInfo[j][1]="0";
this.dayInfo[j][2]="0";
}
}
public int getDayCount() {
return dayCount;
}
public void setDayCount(int dayCount) {
this.dayCount = dayCount;
}
public String[][] getDayInfo() {
return dayInfo;
}
public void setDayInfo(String[][] dayInfo) {
this.dayInfo = dayInfo;
}
}
package com.fanshe.obj;
import java.lang.reflect.*;
import java.io.IOException;
/**
*获取指定类的构造器相关信息
*/
public class ConstructorTest
{
private int i;
private double j;
//默认的构造器
public ConstructorTest(){
}
//重载的构造器
public ConstructorTest(int i,double j)throws IOException{
this.i=i;
this.j=j;
}
public static void main(String[] args) throws Exception
{
//得到本类的类对象
Class<?> cls=Class.forName("com.fanshe.obj.ConstructorTest");
//取得所有在本类声明的构造器
Constructor<?> []cs=cls.getDeclaredConstructors();
//遍历
System.out.println("----------------");
for(Constructor<?> c:cs){
//构造器名称
System.out.println("构造器名="+c.getName());
//构造器声明所在的类
System.out.println("其声明的类="+c.getDeclaringClass());
//取得参数的类型集合
Class<?> []ps=c.getParameterTypes();
//遍历参数类型
for(int i=0;i<ps.length;i++){
System.out.println("参数类型"+i+"="+ps[i]);
}
//取得异常的类型集合
Class<?> []es=c.getExceptionTypes();
//遍历异常类型
for(int j=0;j<es.length;j++){
System.out.println("异常类型"+j+"="+es[j]);
}
//结束一层循环标志
System.out.println("-----------");
}
}
}
package com.fanshe.obj;
import java.lang.reflect.*;
/**
*通过反射创新类的新对象
*/
class CreateNewObj
{
//显式默认的构造器
public CreateNewObj(){
}
//重载构造器
public CreateNewObj(int a,int b){
System.out.println("a= "+a+" b="+b);
}
public static void main(String[] args) throws Exception
{
//得到本类的类对象
Class<?> c=Class.forName("com.fanshe.obj.CreateNewObj");
//声明构造器的参数类型集合
Class<?> []paramTypes=new Class[2];
//都为int型
paramTypes[0]=Integer.TYPE;
paramTypes[1]=Integer.TYPE;
//根据参数类型决定得到哪个构造器
Constructor<?> cs=c.getConstructor(paramTypes);
//声明要传入的参数集合
Object []argList=new Object[2];
//传入37和43
argList[0]=new Integer(37);
argList[1]=new Integer(43);
//根据符合上述参数类型的构造器来创建新的对象
Object rtnObj=cs.newInstance(argList);
}
}
package com.fanshe.obj;
import java.lang.reflect.*;
/**
*获取指定类的字段相关信息
*/
class FieldTest
{
//字段1
private double d;
//字段2
public static final int i=37;
//字段3
String str="fieldstest";
public static void main(String[] args) throws Exception
{
//获取本类的类对象
Class<?> c=Class.forName("com.fanshe.obj.FieldTest");
//获取所有声明的的字段,getFields()包括继承来的字段
Field []fs=c.getDeclaredFields();
//遍历
for(int i=0;i<fs.length;i++){
Field f=fs[i];
//字段名
System.out.println("字段名"+(i+1)+"="+f.getName());
//字段声明所在的类
System.out.println("该字段所在的类为:"+f.getDeclaringClass());
//字段的类型
System.out.println("字段"+(i+1)+"的类型:"+f.getType());
//查看修饰符
int mod=f.getModifiers();
//为0就是默认的包类型
if(mod==0){
System.out.println("该字段的修饰符为:默认包修饰符");
}else{
//否则就是相应的类型
System.out.println("该字段的修饰符为:"+Modifier.toString(mod));
}
System.out.println("---结束第"+(i+1)+"循环---");
}
}
}
package com.fanshe.obj;
import java.lang.reflect.*;
/**
*获取指定类的方法相关信息
*/
class InformationTest
{
public static void main(String[] args) throws Exception
{
//得到String类对象
Class<?> cls=Class.forName("java.lang.String");
//得到所有的方法,包括从父类继承过来的方法
Method []methList=cls.getMethods();
//下面是得到的是String类本身声明的方法
//Method []methList=cls.getDeclaredMethods();
//遍历所有的方法
for(Method m:methList){
//方法名
System.out.println("方法名="+m.getName());
//方法声明所在的类
System.out.println("声明的类="+m.getDeclaringClass());
//获取所有参数类型的集体
Class<?> []paramTypes=m.getParameterTypes();
//遍历参数类型
for(int i=0;i<paramTypes.length;i++){
System.out.println("参数 "+i+" = "+paramTypes[i]);
}
//获取所有异常的类型
Class<?> []excepTypes=m.getExceptionTypes();
//遍历异常类型
for(int j=0;j<excepTypes.length;j++){
System.out.println("异常 "+j+" = "+excepTypes[j]);
}
//方法的返回类型
System.out.println("返回类型 ="+m.getReturnType());
//结束一层循环标志
System.out.println("---------");
}
}
}
package com.fanshe.obj;
import java.lang.reflect.*;
/**
*通过反射改变字段的值
*/
class ModifyField
{
//声明一个字段
public double d;
public static void main(String[] args) throws Exception
{
//得到类的类对象
Class<?> c=Class.forName("com.fanshe.obj.ModifyField");
//根据字段名得到字段对象
Field f=c.getField("d");
//创建类的实例
ModifyField mf=new ModifyField();
//打印修改前字段的值
System.out.println("修改 "+f.getName()+" 前的值为:"+mf.d);
//修改d的值为12.34
f.setDouble(mf,12.34);
//打印修改后的值
System.out.println("修改 "+f.getName()+" 后的值为:"+mf.d);
}
}
package com.fanshe.obj;
import java.lang.reflect.*;
/**
*通过反射执行类的方法
*/
class PerformMethod
{
//声明一个简单的方法,用于测试
public int add(int a,int b){
return a+b;
}
public static void main(String[] args)throws Exception
{
//获取本类的类对象
Class<?> c=Class.forName("com.fanshe.obj.PerformMethod");
/**
*声明add方法参数类型的集合
*共有两个参数,都为Integer.TYPE
*/
Class<?> []paramTypes=new Class[2];
paramTypes[0]=Integer.TYPE;
paramTypes[1]=Integer.TYPE;
//根据方法名和参数类型集合得到方法
Method method=c.getMethod("add",paramTypes);
//声明类的实例
PerformMethod pm=new PerformMethod();
//传入参数的集合
Object []argList=new Object[2];
//传入37和43
argList[0]=new Integer(37);
argList[1]=new Integer(43);
//执行后的返回值
Object returnObj=method.invoke(pm,argList);
//类型转换下
Integer returnVal=(Integer)returnObj;
//打印结果
System.out.println("方法执行结果为:"+returnVal.intValue());
}
}
package com.fanshe.obj;
import java.lang.reflect.*;
/**
*通过反射来操作数组
*/
class UserArray
{
public static void main(String[] args) throws Exception
{
//得到String类的类对象
Class<?> c=Class.forName("java.lang.String");
//通过Array类的反射创建一个含有10个元素的String类型的数组
Object arr=Array.newInstance(c,10);
//为数组第5个位置元素赋一个值
Array.set(arr,5,"第5个位置元素");
//取得第5个位置元素的值
String s=(String)Array.get(arr,5);
//打印这个元素的值
System.out.println("值为:"+s);
}
}
package com.fanshe.obj;
import java.lang.reflect.*;
/**
*通过反射创建和使用更复杂的数组
*/
class UserArrayComplex
{
public static void main(String[] args) throws Exception
{
//声明数组的维数为5X10X15
int dims[]=new int []{5,10,15};
//创建该类型的数组,元素的类型为Integer
Object arr=Array.newInstance(Integer.TYPE,dims);
//得到第3个10X15的二维数组
Object arrObj=Array.get(arr,3);
//Class c=arrObj.getClass().getComponentType();
//System.out.println(c);
//得到第2维中的第2个15位长度的数组
arrObj=Array.get(arrObj,5);
//然后设置该数组里第10个元素的值为37
Array.set(arrObj,10,37);
//再将数组还原
int [][][]arrCast=(int [][][])arr;
//打印刚刚那个值
System.out.println(arrCast[3][5][10]);
}
}
门面模式是对象的结构模式,外部与一个子系统的通信必须通过一个统一的门面对象进行。门面模式提供一个高层次的接口,使得子系统更易于使用。使用门面模式还有一个附带的好处,就是能够有选择性地暴露方法。一个模块中定义的方法可以分成两部分,一部分是给子系统外部使用的,一部分是子系统内部模块之间相互调用时使用的。有了Facade类,那么用于子系统内部模块之间相互调用的方法就不用暴露给子系统外部了。public interface ServiceA {
void methodA() ;
}
public class ServiceAImpl implements ServiceA{
@Override
public void methodA() {
System.out.println("这是服务A");
}
}
public interface ServiceB {
void methodB() ;
}
public class ServiceBImpl implements ServiceB{
@Override
public void methodB() {
System.out.println("这是服务B");
}
}
public interface ServiceC {
void methodC() ;
}
public class ServiceCImpl implements ServiceC{
@Override
public void methodC() {
System.out.println("这是服务C");
}
}
public class Facade {
ServiceA sa;
ServiceB sb;
ServiceC sc;
public Facade() {
sa = new ServiceAImpl();
sb = new ServiceBImpl();
sc = new ServiceCImpl();
}
public void methodA() {
sa.methodA();
sb.methodB();
}
public void methodB() {
sb.methodB();
sc.methodC();
}
public void methodC() {
sc.methodC();
sa.methodA();
}
}
测试类:
public class Test {
public static void main(String[] args) {
ServiceA sa = new ServiceAImpl();
ServiceB sb = new ServiceBImpl();
sa.methodA();
sb.methodB();
System.out.println("========");
//facade
Facade facade = new Facade();
facade.methodA();
facade.methodB();
facade.methodC();
}
}
推荐免费下载430套大型商业源码
下载地址:http://www.hur.cn/tg/linkin.asp?linkid=200978
PB-商业源码
金科信进销存软件源码(81M)
制造业管理系统源码(257M)
PB连锁药店GSP源码(136M)
创某医院系统源码(813M)
人力资源管理系统源码(182M)
浪某财务系统源码(131M)
医院系统源码(58M)
医院管理软件门诊挂号收费系统源码(83M)
医疗保险管理系统源码(191M)
拓某连锁专卖宝典源码(90M)
普某ERP系统源码(300M)
科某企业ERP源码(154M)
重庆运通商业连锁系统源码(293M)
供电局MIS管理信息系统源码(196M)
社区信息管理系统源码(122M)
暂住人口管理系统4.0(网络版)源码(25M)
高某医院系统源码(200M)
思某商业管理系统源码(40M)
电子厂用小型ERP系统源码(51M)
点某财务软件源码(121M)
和某ERP系统源码(73M)
医院管理系统源码(956M)
河南医院信息系统源码(400M)
瑞某酒店管理系统源码(48M)
飞某商业管理系统源码(87M)
PowerBuilder 8.0 自定义报表系统(5M)
动态报表系统(10M)
致某动态报表模块源码(5M)
小型商业进销存系统(带POS)(34M)
大型酒店管理最新版本PB8(60M)
中小超市POS综合管理系统(142M)
检查科室报告单管理软件(17M)
商某5.0 POS系统(20M)
威某酒店管理系统(365M)
鞋业ERP系统(繁体)(160M)
新某大财务系统(301M)
医生工作站源码(30M)
宏声人力资源管理系统(41M)
医疗保险系统(37M)
医药卫生综合管理系统(54M)
MIS系统源代码pb9(40M)
PB影碟出租管理系统8.03(14M)
pb-oracle通用开发框架(27M)
PB编写的电子地图源码(5M)
大众医院门诊收费系统(28M)
pb洗浴管理系统(9M)
餐饮管理程序源代码(14M)
仓库管理系统源码(6M)
查询打印数据窗口共享排序定制基类(5M)
长江科学院合同成果管理(27M)
工程造价系统源码(17M)
国泰商业管理系统MIS(135M)
华泰印刷源码(122M)
检查科室报告单管理软件(17M)
金华医院门诊挂号收费系统PB(80M)
酒店管理系统(网络版)(73M)
某配件公司生产管理系统(154M)
某企业财务管理系统(125M)
瑞通hms(245M)
瑞通酒店管理系统V8.0网络版(102M)
商场管理系统源代码pb(15M)
商品进销存管理系统(pb)(9M)
天河进销存POS系统(211M)
物流程序源码(53M)
小型商业进销存系统(带POS)(32M)
鞋业ERP源码(153M)
旭日2000企业管理系统(65M)
血库的软件用pb做(6M)
药品管理(27M)
医疗保险系统pb(258M)
普阳Erp源码(61M)
科研管理系统源码(15M)
酒店管理系统(59M)
Delphi-商业源码
美容院管理系统源码(70M)
MRPII制造资源计划系统源码(147M)
ERP企业管理系统源码(74M)
福某制衣MRP管理系统源码(43M)
胜某进销存系统源码(88M)
立某酒店、餐饮、洗浴、休闲管理系统源码(55M)
实某聊天系统 v3.0源码(71M)
社保管理系统源码(22M)
商业通医药连锁经营管理系统源码(40M)
商业管理系统源码(135M)
日某餐饮系统源码(173M)
企业进销存系统源码(41M)
贸易网站登陆器源码(60M)
遵某的视频会议系统代码源码(26M)
贸易管理系统源码(65M)
酒店管理系统源码(106M)
汽车租赁信息咨询系统源码(62M)
牙科诊所管理系统源码(31M)
制衣MRPII系统源码(65M)
中国眼科病历系统源码(103M)
远程控制源码(20M)
医药连锁源码源码(55M)
语音故障报修系统(需要TW8VID语音卡)源码(18M)
行业应急系统源码(23M)
销售管理系统源码(24M)
洗浴中心管理系统源码(20M)
五金管理信息系统源码(18M)
网络教室系统源码(网络版)源码(58M)
天某ERP系统源码(281M)
医院病案管理系统源码(26M)
VOD点歌系统源码(59M)
国外的财务软件源码(126M)
旅游公司信息系统源码(43M)
人力资源管理系统源码(24M)
POS超市管理系统源码(60M)
POS系统源码(43M)
医院收费与信息管理系统源码(122M)
安某销售系统源码(10M)
GIS系统—有线电视网络设备管理系统源码(30M)
ICQ(客服服务器)源码(55M)
办公自动化系统源代码源码(27M)
仓储物流信息管理系统源码(137M)
传奇游戏源码(178M)
电能表载波抄表软源码(44M)
电子试卷生成系统源码(30M)
美容院管理系统源码(16M)
泰某工程管理软件源码(40M)
环某美容美发管理系统源码(23M)
机房收费管理源码(78M)
计划生育管理系统源码(21M)
驾驶员考试源码(40M)
金某验布系统源码(82M)
进销存系统源码(43M)
超市库存管理系统源码(23M)
中移动大客户管理系统(7M)
思微pos系统(48M)
泰达图书馆工程管理软件源码(24M)
Delphi编写的企业进销存系统源代码(11M)
ENO企业人事信息管理系统(6M)
NiceERP企业系统(42M)
ST进销存源码(12M)
宾馆软件源码(12M)
采购应用系统源码(11M)
超市管理系统源代码(7M)
非常方便的物业管理系统(7M)
钢铁进销存源码(12M)
港汇客户管理系统源码(13M)
海信商业管理系统完整源码版(99M)
进销存ForD7(8M)
牧羊人服饰系统 (ADO+SQL)(6M)
实达企业在线EOL三层系统Delphi源码(11M)
手机营销系统源码(10M)
通用的进销存系统源码(10M)
通用人力资源系统源码(7M)
完整的市一级工资管理程序源码(142M)
西恩软件机房管理源码(26M)
信息管理程序源码(14M)
制衣MRP管理系统源码(45M)
胜天财务进销存2003源码(82M)
AL源码(10M)
DAGL 档案管理程序 v1.0 (SQL Server)(22M)
delphi BookMIS 教材管理系统(7M)
delphi_宏远VOD原代码(45M)
大型企业ERP管理系统(84M)
大型企业邮件管理系统(7M)
delphi_柯龙中草药进销存 v3.0(22M)
delphi_企业管理Erp(64M)
delphi_思微POS连锁超市管理系统(60M)
delphi个人理财软件源码(7M)
delphi名佳商务系统源码(74M)
delphi万家福超市管理系统(17M)
delphi物流供应链管理系统(5M)
delphi医院管理系统(18M)
delphi咏南进销存 两层(C_S)(8M)
NDOA南都办公自动化系统(delphi)(8M)
POS连锁超市管理系统 (商业代码)(60M)
delphi灰鸽子vip1.2 版本(43M)
地磅称量系统(7M)
典当综合业务管理系统(10M)
电子寻更源程序(20M)
东莞和富有限公司进销存管理系统(33M)
动感立体KTV VOD(18M)
工资管理系统(53M)
广电行业GIS系统(10M)
华丝贸易国内销售管理系统(30M)
火锅城管理系统1.0版(10M)
机动车驾驶员无纸化理论考试系统(38M)
局域网即时通信系统(52M)
客房管理系统(网络版)(100M)
客户关系管理系统(CRM)(11M)
力信消费管理系统2000(12M)
龙邦进销存源码(16M)
美容院管理系统修改版(ADO)(21M)
某公司工资管理系统(17M)
某企业ERP企业管理系统(32M)
某通用进销存系统(20M)
配件仓库管理(24M)
企业管理Erp(商业源码)(64M)
全球数码仓库仓储管理信息系统(110M)
思雷特(sunnet)物业管理信息系统(232M)
台湾公司做的一个ERP管理系统(235M)
万佳圆宾馆桑拿洗浴管理系统(20M)
网络营销专家(25M)
维修管理工具(15M)
五金材料商业进销存(23M)
物业管理(22M)
校园网多媒体自动播放系统(10M)
新艺VOD系统(59M)
眼镜行业财务进销存后台管理代码 V1.0v(72M)
异洲酒店(餐饮)管理系统delphi源码(delphi+sql)(20M)
P2P即时通讯源码Delphi(46M)
POS消费管理系统2000delhi源码(12M)
大型超市销售连锁管理系统(16M)
电子寻更源程序delphi(20M)
远程控制DELPHI源代码(17M)
高考网上招生省招办投档系统(11M)
湖南佳某软件公司商业POS通系统delphi源码(98M)
化工颜料生产管理源码(30M)
科技计划信息管理系统delphi源码(22M)
视频会议系统delphi源码(45M)
某医院HIS管理系统delphi源码(86M)
顺某指纹考勤管理系统delphi源码(64M)
delphi超市管理系统源码(16M)
VB-商业源码
新世某ERP5.0升级版源码(796M)
MIS管理信息系統源码(583M)
医药卫生管理系统源码(60M)
制造业ERP系统源码(125M)
专卖店POS系统源码(36M)
售房管理系统源码(89M)
用某u850源码(9M)
易某点歌系统源码(18M)
医院系统源码(202M)
医药管理GSP源码(36M)
新开某酒店系统源码(29M)
网吧管理系统源码(15M)
太平某信息管理系统源码(33M)
金算某财务及企业管理软件源码(134M)
教师住房管理系统源码(12M)
惠某ERP系统源码(442M)
报业广告发行管理系统源码(42M)
宝某售饭系统源码(15M)
新世某ERP5.0完全版源码(399M)
宛某书社图书管理系统源码(9M)
VB+SQL开发银行模拟系统(167M)
VB超巿管理系统(11M)
材料目录软件(10M)
进销存软件(13M)
全球通商务管理系统——POS管理系统(另一版本)(75M)
四季青污水处理厂系统(62M)
网吧管理系统服务器客户端源程序(另一版本)(15M)
住房公积金监管系统(46M)
邮件管理与群发系统(30M)
学生信息管理系统(5M)
通用文档一体化档案管理系统(127M)
升瑞售楼管理系统(60M)
设计系统2000(报表设计与管理系统)(12M)
人力资源管理系统(28M)
网络营销软件(25M)
某企业物资管理信息系统(14M)
某计算机网络管理系统VB(74M)
财务系统源码(70M)
路桥收费系统VB(702M)
大型企业内部管理系统(228M)
伯乐人力资源管理系统2000(161M)
北京市区绿化隔离地区信息系统2000(34M)
学生信息管理系统v1.0(附源码)(5M)
馨香物业管理糸统(13M)
新版图书综合管理系统(6M)
审核管理系统-完整版(35M)
华成酒店管理系统(10M)
大型商业ERP系统2-财务系统部分(65M)
超市销售管理系统(5M)
宾馆桑拿休闲中心管理系统(30M)
宾馆客房管理系统(6M)
vb酒店管理系统(10M)
VB物流管理系统源码(11M)
计划生育管理系统(56M)
vb和Mapx开发的房屋测绘系统GIS商业源码(10M)
乡镇供电所电费处理系统(14M)
VB人事工资管理系统(27M)
VB财务软件源码(19M)
VC-商业源码
网络听诊管理监控系统源码(1540M)
速某(c++)MRPII系统源码(320M)
贸易网站登陆器源码(60M)
工厂自动化生产整合管理系统源码(233M)
高速公路收费系统源码(44M)
北京某大卖场公司自主开发首套linux平台Pos源码(245M)
酒店餐饮管理系统(21M)
伯克公司生产销售系统源码(14M)
企业短信助理源代码(20M)
一个超完整的医药管理系统源码(59M)
综合人事管理系统源码(vc+sql2000)(18M)
综合人事管理系统源码(vc+sql2000)(5M)
Hotel酒店管理系统源码(4M)
POS前台C++程序源码(7M)
quakeIII 源码(26M)
视频会议系统源码(50M)
VC客房管理系统源码(10M)
VC数字图像模式技术及工程应用源码(106M)
串口编程调试及双机互联源码(44M)
代码名称:Microsoft MS-DOS6.0 完整源代码(63M)
家族信息管理系统源码(7M)
酒店管理系统2003(8M)
考勤管理系统源代码下载(9M)
利用MFC开发的OpenGL开发包(27M)
屏幕转换成AVI文件的程序源码(25M)
赛克思书店销售管理系统源码(7M)
数字图像处理源码(30M)
数字图像获取、处理与分析源盘(42M)
图形图象类代码(8M)
用Visual C++开发GIS系统(16M)
游戏编程精粹源码(36M)
云台镜头控制系统源码(20M)
智能安防报警系统源码(37M)
Vc视频会议源代码压缩文件(314M)
VC数字图像模式技术及工程应用(103M)
vc医院门诊收费系统(5M)
互联天下im(95M)
某公司VC视频核心代码(35M)
视频会议开发代码(259M)
视频监控(55M)
视音频代码(35M)
用Visual C++开发GIS系统(15M)
真正的速达源码(CB5可编译)(54M)
IM企业即时通讯软件源代码(18M)
宾馆酒店管理系统源码(25M)
可视电话软件源码(16M)
商品采购管理系统vc源码(25M)
网络视频会议系统vc源码(41M)
.NET-商业源码
和某大型ERP系统源码(510M)
商务管理教学源码(28M)
C#写的网上汽修汽配管理系统(52M)
企业公文管理信息系统(87M)
教材管理中心(3M)
商务之星(ASP.NET)(618M)
物流系统Logistics(v1.0)(217M)
若冰.net远程教育系统(18M)
asp.net+c#的人事系统(2M)
Coffice协同办公管理系统(C#)(176M)
NET的bbs论坛源码(6M)
OA办公自动化系统源码(21M)
嘉惠药品进销存管理系统(vb.net)(55M)
企业内部信息交流系统源码(9M)
若冰企业商务平台.net(31M)
数据结构动画演示系统(c#)DataStructure(8M)
医院管理系统ASP.NET+MSSQL(9M)
中铁五局Mis系统原型设计(9M)
住房公积金管理中ASP.NET+MSSQL(5M)
房地产信息网(c#.net+sql)(6M)
net网上购书系统(11M)
NET药品进销存系统(5M)
net采购仓库核销管理系统(6M)
net计算机基础考试系统(10M)
net精品OA(91M)
net客户关系管理系统(6M)
net企业客户服务系统(5M)
net企业销售管理信息系统(8M)
net汽车销售公司ERP进销存系统(38M)
net图书馆管理系统(11M)
net学生寝室管理系统(12M)
net真正的全动态报表(5M)
net自定义报表(16M)
vb.net 销售管理系统(5M)
vbnet进销存系统源码(6M)
多层架构的大型.NET OA 系统(16M)
客户关系管理系统(8M)
某公司CRM管理系统 net(29M)
三甲医院管理系统HIS(C#版)(27M)
局域网考试系统C#(9M)
进出仓管理系统(17M)
Asp.Net用友华表(V5.1)制作自定义报表(16M)
Asp.net通用OA系统源代码(12M)
C#酒店管理系统(20M)
PowerOA办公自动化系统商业源码(15M)
餐饮管理系统(C#源码)(32M)
公司客户关系管理系统CRM ASP.NET源码(27M)
机械制造业信息管理系统源码(21M)
C#某橱柜销售企业ERP管理系统(16M)
公司的业务管理系统(15M)
商业进销管理系统(47M)
公路运输管理系统asp.net(30M)
汽车销售公司ERP进销存系统(39M)
现代教务管理系统源码(25M)
药店管理系统(33M)
餐饮管理系统源码(10M)
智能办公系统(14M)
JAVA-商业源码
大型企业JAVA的ERP源码(193M)
可乐吧在线游戏最新服务器端及部分源代码源码(18M)
华某物业管理系统源码-JSP源码(97M)
华某物业管理系统安装程序源码(43M)
乐趣大型购物系统源码(7M)
Java做的WebMail源码(9M)
JAVA进销存源码(60M)
哈工大CERP系统源码(17M)
JSP开发的项目跟踪系统源码(11M)
季风进销存管理系统1.1(JSP版)源码(4M)
java框架开源订销管理系统MYSQL(6M)
条形码商品管理信息系统源码(12M)
信用卡管理系统源码(4M)
学生课绩管理系统(5M)
工作流管理系统openwfe源码(38M)
开源网上会议系统iula-0.1.0 java(5M)
java 学生管理系统(全部代码+数据库)(5M)
java超市购物系统(9M)
java网上oa办公系统原码(5M)
JAVA写的个人博客源码(8M)
java阳光酒店管理系统(14M)
投票管理系统java(16M)
宠物销售管理系统 java(11M)
网站在线客服系统(Jsp+MySql)(19M)
企富商贸网 java(12M)
商城之家JSP商城企业版v6.8(15M)
石大在线财务管理系统(含源码)java(5M)
AWT图形设计源代码(9M)
iText可以制作中文PDF文件的JAVA源程序(5M)
Java+sqlserver2000做的员工管理系统(5M)
6JAVA的ICQ系统源码(7M)
Java开发的网络办公系统(33M)
Java设计源码(25M)
Java做的WebMail(9M)
雇员管理系统源码(5M)
酒店管理系统(16M)
员工管理系统(8M)
CRM客户管理系统源代码(12M)
J2EE项目源码DigitalCampus数字校园(17M)
JAVA网上商城项目完整源码(10M)
Java实现图书馆管理系统源码(13M)
Java写的ERP系统(30M)
java大型企业DRP分销系统源码(11M)
CRM项目java源码(10M)
JBuilder固定资产管理系统java项目源码(12M)
基于J2EE三层结构设计ERP源码(12M)
..............
<!-- 配置方法级别的校验 -->
<interceptor-ref name="validation">
<param name="excludeMethods">input,back,cancel,browse</param>
<param name="validateAnnotatedMethodOnly">true</param>
</interceptor-ref>
所以action中的这四个方法不需要验证
// 保存
@Validations(
requiredStrings = {
@RequiredStringValidator(fieldName = "admin.username", message = "用户名不允许为空!"),
@RequiredStringValidator(fieldName = "admin.password", message = "密码不允许为空!"),
@RequiredStringValidator(fieldName = "admin.email", message = "E-mail不允许为空!")
},
requiredFields = {
@RequiredFieldValidator(fieldName = "admin.isAccountEnabled", message = "是否启用不允许为空!")
},
stringLengthFields = {
@StringLengthFieldValidator(fieldName = "admin.username", minLength = "2", maxLength = "20", message = "用户名长度必须在${minLength}到${maxLength}之间!"),
@StringLengthFieldValidator(fieldName = "admin.password", minLength = "4", maxLength = "20", message = "密码长度必须在${minLength}到${maxLength}之间!")
},
emails = {
@EmailValidator(fieldName = "admin.email", message = "E-mail格式错误!")
},
regexFields = {
@RegexFieldValidator(fieldName = "admin.username", expression = "^[0-9a-z_A-Z\u4e00-\u9fa5]+$", message = "用户名只允许包含中文、英文、数字和下划线!")
}
)
一个轻量级的cookie 插件,可以读取、写入、删除 cookie。
jquery.cookie.js 的配置
首先包含jQuery的库文件,在后面包含 jquery.cookie.js 的库文件。
<script type="text/javascript" src="js/jquery-1.6.2.min.js"></script>
<script type="text/javascript" src="js/jquery.cookie.js"></script>
使用方法
1.新添加一个会话 cookie:
$.cookie('the_cookie', 'the_value');
注:当没有指明 cookie有效时间时,所创建的cookie有效期默认到用户关闭浏览器为止,所以被称为
“会话cookie(session cookie)”。
2.创建一个cookie并设置有效时间为 7天:
$.cookie('the_cookie', 'the_value', { expires: 7 });
注:当指明了cookie有效时间时,所创建的cookie被称为“持久 cookie (persistent cookie)”。
3.创建一个cookie并设置 cookie的有效路径:
$.cookie('the_cookie', 'the_value', { expires: 7, path: '/' });
注:在默认情况下,只有设置 cookie的网页才能读取该 cookie。如果想让一个页面读取另一个页面设
置的cookie,必须设置cookie的路径。cookie的路径用于设置能够读取 cookie的顶级目录。将这
个路径设置为网站的根目录,可以让所有网页都能互相读取 cookie (一般不要这样设置,防止出现冲突) 。
4.读取cookie:
$.cookie('the_cookie'); // cookie存在 => 'the_value'
$.cookie('not_existing'); // cookie不存在 => null
5.删除cookie,通过传递null作为cookie的值即可:
$.cookie('the_cookie', null);
----------相关参数的解释---------------
1).expires: 365
定义cookie的有效时间,值可以是一个数字(从创建cookie时算起,以天为单位)或一个Date 对
象。如果省略,那么创建的cookie是会话cookie,将在用户退出浏览器时被删除。
2).path: '/'
默认情况:只有设置cookie的网页才能读取该cookie。
定义cookie的有效路径。默认情况下, 该参数的值为创建 cookie 的网页所在路径(标准浏览器的行为) 。
如果你想在整个网站中访问这个cookie需要这样设置有效路径:path: '/'。如果你想删除一个定义
了有效路径的 cookie,你需要在调用函数时包含这个路径:$.cookie('the_cookie', null,
{ path: '/' });。 domain: 'example.com'
默认值:创建 cookie的网页所拥有的域名。
3).secure: true
默认值:false。如果为true,cookie的传输需要使用安全协议(HTTPS)。
4).raw: true
默认值:false。
默认情况下,读取和写入 cookie 的时候自动进行编码和解码(使用encodeURIComponent 编码,
decodeURIComponent 解码)。要关闭这个功能设置 raw: true 即可。
public class DBHelp<T> {
private static String driver;
private static String url;
private static String username;
private static String password;
private static BasicDataSource dataSource;
static{
Properties properties = new Properties();
try {
//读取到src目录中存放的db.properties配置文件
properties.load(DBHelp.class.getClassLoader().getResourceAsStream("db.properties"));
driver = properties.getProperty("driver");
url = properties.getProperty("url");
username = properties.getProperty("username");
password = properties.getProperty("password");
} catch (IOException e) {
e.printStackTrace();
}
dataSource = new BasicDataSource();
dataSource.setDriverClassName(driver);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
dataSource.setInitialSize(5);
dataSource.setMaxWait(5000);
dataSource.setMaxActive(20);
dataSource.setMinIdle(10);
}
public Connection getConnection(){
try {
Connection conn = dataSource.getConnection();
return conn;
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
public List<T> executeForList(RowMapper<T> rowMapper,String sql) {
Connection conn = null;
PreparedStatement stat = null;
ResultSet rs = null;
List<T> list = new ArrayList<T>();
try {
conn = getConnection();
stat = conn.prepareStatement(sql);
rs = stat.executeQuery();
while(rs.next()) {
list.add(rowMapper.mapperRow(rs));
}
System.out.println("SQL"+sql);
} catch (SQLException e) {
e.printStackTrace();
}finally{
close(rs, stat, conn);
}
return list;
}
public List<T> executeForList(String sql,RowMapper<T> rowMapper,Object... args) {
Connection conn = null;
PreparedStatement stat = null;
ResultSet rs = null;
List<T> list = new ArrayList<T>();
try {
conn = getConnection();
stat = conn.prepareStatement(sql);
for (int i = 0; i < args.length; i++) {
stat.setObject(i+1,args[i]);
}
rs = stat.executeQuery();
while(rs.next()) {
list.add(rowMapper.mapperRow(rs));
}
System.out.println("SQL"+sql);
} catch (SQLException e) {
e.printStackTrace();
}finally{
close(rs, stat, conn);
}
return list;
}
public T executeForObject(String sql,RowMapper<T> rowMapper,Object... args) {
Connection conn = null;
PreparedStatement stat = null;
ResultSet rs = null;
T obj = null;
try {
conn = getConnection();
stat = conn.prepareStatement(sql);
for (int i = 0; i < args.length; i++) {
stat.setObject(i+1, args[i]);
}
rs = stat.executeQuery();
if(rs.next()) {
obj = rowMapper.mapperRow(rs);
}
System.out.println("SQL"+sql);
} catch (SQLException e) {
e.printStackTrace();
}finally{
close(rs, stat, conn);
}
return obj;
}
public int executeForCount(String sql,Object... args){
Connection conn = null;
PreparedStatement stat = null;
ResultSet rs = null;
int count = 0;
try {
conn = getConnection();
stat = conn.prepareStatement(sql);
rs = stat.executeQuery();
for(int i = 0;i < args.length;i++){
stat.setObject(i+1, args[i]);
}
if(rs.next()) {
count = rs.getInt(1);
}
System.out.println("SQL"+sql);
} catch (SQLException e) {
e.printStackTrace();
}finally{
close(rs, stat, conn);
}
return count;
}
public void executeUpdate(String sql,Object... args) {
Connection conn = null;
PreparedStatement stat = null;
try {
conn = getConnection();
stat = conn.prepareStatement(sql);
for(int i = 0;i < args.length;i++){
stat.setObject(i+1, args[i]);
}
stat.executeUpdate();
System.out.println("SQL"+sql);
} catch (SQLException e) {
e.printStackTrace();
}finally{
close(stat,conn);
}
}
public void close(PreparedStatement stat,Connection conn) {
close(null,stat,conn);
}
public void close(ResultSet rs,PreparedStatement stat,Connection conn) {
try {
if(rs != null){
rs.close();
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
try {
if(stat != null) {
stat.close();
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
try {
if(conn != null) {
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
public interface RowMapper<T> {
public T mapperRow(ResultSet rs) throws SQLException;
}
public class TourDao {
private DBHelp<Tour> db = new DBHelp<Tour>();
public Tour findByName(String name){
String sql = "SELECT id,tourname FROM t_tour WHERE tourname=?";
Tour t = db.executeForObject(sql, new TourRowMapper(), name);
return t;
}
public void insertSale(String name){
String sql = "INSERT INTO t_tour (tourname) VALUE(?)";
db.executeUpdate(sql, name);
}
public class TourRowMapper implements RowMapper<Tour>{
public Tour mapperRow(ResultSet rs) throws SQLException {
Tour t = new Tour();
t.setId(rs.getInt("id"));
t.setTourname(rs.getString("tourname"));
return t;
}
}
}
备忘录(Memento)模式又称标记(Token)模式。GOF给备忘录模式的定义为:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。
其实单就实现保存一个对象在某一时刻的状态的功能,还是很简单的——将对象中要保存的属性放到一个专门管理备份的对象中,需要的时候则调用约定好的方法将备份的属性放回到原来的对象中去。
备忘录模式的组成部分:
1) 备忘录(Memento)角色:备忘录角色存储“备忘发起角色”的内部状态。“备忘发起角色”根据需要决定备忘录角色存储“备忘发起角色”的哪些内部状 态。为了防止“备忘发起角色”以外的其他对象访问备忘录。备忘录实际上有两个接口,“备忘录管理者角色”只能看到备忘录提供的窄接口——对于备忘录角色中 存放的属性是不可见的。“备忘发起角色”则能够看到一个宽接口——能够得到自己放入备忘录角色中属性。
2) 备忘发起(Originator)角色:“备忘发起角色”创建一个备忘录,用以记录当前时刻它的内部状态。在需要时使用备忘录恢复内部状态。
3) 备忘录管理者(Caretaker)角色:负责保存好备忘录。不能对备忘录的内容进行操作或检查。
使用备忘录模式的前提:
1) 必须保存一个对象在某一个时刻的(部分)状态, 这样以后需要时它才能恢复到先前的状态。
2) 如果一个用接口来让其它对象直接得到这些状态,将会暴露对象的实现细节并破坏对象的封装性。
例子如下:
//存储信息类
public class Caretaker {
private Memento memento;
public Memento getMemento(){
return this.memento;
}
public void setMemento(Memento memento){
this.memento = memento;
}
}
//备忘录模式
public class Memento {
private String state;
public Memento(String state) {
this.state = state;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
}
public class Originator {
private String state;
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public Memento createMemento() {
return new Memento(state);
}
public void setMemento(Memento memento) {
state = memento.getState();
}
public void showState(){
System.out.println(state);
}
}
测试类:
public class Test {
public static void main(String[] args) {
Originator org = new Originator();
org.setState("开会中");
org.showState();//显示
System.out.println("---------------");
Caretaker ctk = new Caretaker();
ctk.setMemento(org.createMemento());//将数据封装在Caretaker
System.out.println("---------------");
org.setState("睡觉中");
org.showState();//显示
System.out.println("---------------");
org.setMemento(ctk.getMemento());//将Caretaker中的数据重新导入
org.showState();
System.out.println("---------------");
}
}
Java深入到一定程度,就不可避免的碰到设计模式这一概念,了解设计模式,将使自己对java中的接口或抽象类应用有更深的理解.设计模式在java的 中型系统中应用广泛,遵循一定的编程模式,才能使自己的代码便于理解,易于交流,Mediator(中介者模式)模式是比较常用的一个模式.
Mediator中介者模式,当多个对象彼此间都有联系的时候,我们就可以应用Mediator将对象间的多对多关系转换为一对多的关系,这样做,可以使各个对象间的耦合松散。统一管理对象间的交互。但也可能使得Mediator对象成为一个系统中的庞然大物,难以维护
使用场景:集中负责维护对象模型的关系完整性 以及需要 封装对象间交互方式的时候.
其实MVC中的controller就是一种Mediator,是UI层 和后端应用sevice层间的中介者。中介者将交互的复杂性变为中介者的复杂性
例子如下:
业务类的接口:
public interface Colleague {
void action();
}
业务类的2个实现类:
public class ColleagueA implements Colleague{
@Override
public void action() {
System.out.println("普通员工努力工作aaaaaaa");
}
}
public class ColleagueB implements Colleague{
@Override
public void action() {
System.out.println("前台注意了bbbb");
}
}
中介者接口:
public interface Mediator {
void notice(String content);
}
public class ConcreteMediator implements Mediator{
private ColleagueA ca;
private ColleagueB cb;
public ConcreteMediator() {
ca = new ColleagueA();
cb = new ColleagueB();
}
public void notice(String content) {
if (content.equals("boss")) {
//老板来了, 通知员工A
ca.action();
}
if (content.equals("client")) {
//客户来了, 通知前台B
cb.action();
}
}
}
测试类:
public class Test {
public static void main(String[] args) {
Mediator med = new ConcreteMediator();
//老板来了
med.notice("boss");
//客户来了
med.notice("client");
}
}
当客户端传过来的字符串不一样时,中介者类根据字符串实现不同的业务类的对象,处理数据。
function isInRect(x, y, x0, y0, x1, y1) {
if (x0 < x && x < x1 && y0 < y && y < y1)
return true;
else
return false;
}
function ElIn(elId) {
var el = Ext.get(elId);
el.fadeIn( {
endOpacity : 1,
easing : 'easeOut',
duration : 2
});
}
function ElOut(elId) {
var el = Ext.get(elId);
el.fadeOut( {
endOpacity : 0,
easing : 'easeOut',
duration : .5,
useDisplay : true
});
// el.dom.style.display = 'none';
}
function getClickScale(event, target, isShowInfo) {
var imageWidth = target.width;
var imageHeight = target.height;
var eventX = event.xy[0];
var eventY = event.xy[1];
var scalex = eventX / imageWidth;
var scaley = eventY / imageHeight;
var info = '';
info += 'image (' + imageWidth + ', ' + imageHeight + '), ';
info += 'click (' + eventX + ', ' + eventY + '), ';
info += 'scale (' + scalex + ', ' + scaley + ')';
if (typeof (isShowInfo) != 'undefined' && isShowInfo) {
alert(info);
}
return {
scalex : scalex,
scaley : scaley
};
}
Ext.get('main-navigator-image').on(
'mousemove',
function(event, target, obj) {
var scale = getClickScale(event, target);
target.style.cursor = '';
for ( var i = 0; i < areas.length; i++) {
var area = areas[i];
if (isInRect(scale.scalex, scale.scaley,
area.p1.scalex, area.p1.scaley,
area.p2.scalex, area.p2.scaley)) {
target.style.cursor = 'pointer';
break;
}
}
});
});
1.在tomcat的service.xml中把端口改成80
2.把自己的项目名称改成ROOT,覆盖tomcat的原ROOT项目,就可以了
var combo = new Ext.form.ComboBox(
{
store : store,
emptyText : '请选择',
mode : 'local',
triggerAction : 'all',
valueField : 'value',
displayField : 'name',
//autoScroll : true,
//length : 4,
//IdValue : 'name',
listeners : {//选择一行后触发的事件
'select' : function() {
var url = combo
.getValue();//得到valueField的值
if (url != null
&& url != '') {
loactionTo(
combo
.getRawValue(),//得到displayField的值
url);
// typeForm.getForm().submit({});
}
}
}
});
hibernate抓取策略(单端代理的批量抓取)
保持默认,同fetch="select",如:
<many-to-one name="classes" column="classesid" fetch="select"/>
fetch="select",另外发送一条select语句抓取当前对象关联实体或集合
设置fetch="join",如:
<many-to-one name="classes" column="classesid" fetch="join"/>
fetch="join",hibernate会通过select语句使用外连接来加载其关联实体或集合
此时lazy会失效
hibernate抓取策略(集合代理的批量抓取)
保持默认,同fetch="select",如:
<set name="students" inverse="true" cascade="all" fetch="select">
fetch="select",另外发送一条select语句抓取当前对象关联实体或集合
设置fetch="join",如:
<set name="students" inverse="true" cascade="all" fetch="join">
fetch="join",hibernate会通过select语句使用外连接来加载其关联实体或集合 此时lazy会失效
设置fetch="subselect",如:
<set name="students" inverse="true" cascade="all" fetch="subselect">
fetch="subselect",另外发送一条select语句抓取在前面查询到的所有实体对象的关联集合
hibernate抓取策略,,batch-size在<class>上的应用
batch-size属性,可以批量加载实体类,参见:Classes.hbm.xml
<class name="Classes" table="t_classes" batch-size="3">
hibernate抓取策略,batch-size在集合上的应用
batch-size属性,可以批量加载实体类,参见:Classes.hbm.xml
<set name="students" inverse="true" cascade="all" batch-size="5">
hibernate 会下先完发sql,再一次性的大数据
实体类父类:
public class Animal {
private int id;
private String name;
private boolean sex;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isSex() {
return sex;
}
public void setSex(boolean sex) {
this.sex = sex;
}
}
子类:
public class Bird extends Animal {
private int height;
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
}
public class Pig extends Animal {
private int weight;
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
}
extends.hbm.xml文件:
<hibernate-mapping package="com.hibernate">
<class name="Animal" abstract="true">
<id name="id">
<generator class="assigned"/>
</id>
<property name="name"/>
<property name="sex"/>
<union-subclass name="Pig" table="t_pig">
<property name="weight"/>
</union-subclass>
<union-subclass name="Bird" table="t_bird">
<property name="height"/>
</union-subclass>
</class>
</hibernate-mapping>
数据库表如下:
父类实体类:
public class Animal {
private int id;
private String name;
private boolean sex;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isSex() {
return sex;
}
public void setSex(boolean sex) {
this.sex = sex;
}
}
子类实体类:
public class Bird extends Animal {
private int height;
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
}
public class Pig extends Animal {
private int weight;
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
}
extends.hbm.xml文件:
<hibernate-mapping package="com.hibernate">
<class name="Animal" table="t_animal">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<property name="sex"/>
<joined-subclass name="Pig" table="t_pig">
<key column="pid"/>
<property name="weight"/>
</joined-subclass>
<joined-subclass name="Bird" table="t_bird">
<key column="bid"/>
<property name="height"/>
</joined-subclass>
</class>
</hibernate-mapping>
在数据库中表如下:
public class Animal {
private int id;
private String name;
private boolean sex;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isSex() {
return sex;
}
public void setSex(boolean sex) {
this.sex = sex;
}
}
public class Bird extends Animal {
private int height;
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
}
public class Pig extends Animal {
private int weight;
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
}
在extends.hbm.xml文件:
<hibernate-mapping package="com.hibernate">
<class name="Animal" table="t_animal" lazy="false">
<id name="id">
<generator class="native"/>
</id>
<discriminator column="type" type="string"/>
<property name="name"/>
<property name="sex"/>
<subclass name="Pig" discriminator-value="P">
<property name="weight"/>
</subclass>
<subclass name="Bird" discriminator-value="B">
<property name="height"/>
</subclass>
</class>
</hibernate-mapping>
理解如何映射
因为类继承树肯定是对应多个类,要把多个类的信息存放在一张表中,必须有某种机制来区分哪些记录是属于哪个类的。
这种机制就是,在表中添加一个字段,用这个字段的值来进行区分。用hibernate实现这种策略的时候,有如下步骤:
父类用普通的<class>标签定义
在父类中定义一个discriminator,即指定这个区分的字段的名称和类型
如:<discriminator column=”XXX” type=”string”/>
子类使用<subclass>标签定义,在定义subclass的时候,需要注意如下几点:
Subclass标签的name属性是子类的全路径名
在Subclass标签中,用discriminator-value属性来标明本子类的discriminator字段(用来区分不同类的字段)
的值Subclass标签,既可以被class标签所包含(这种包含关系正是表明了类之间的继承关系),也可以与class标
签平行。 当subclass标签的定义与class标签平行的时候,需要在subclass标签中,添加extends属性,里面的值
是父类的全路径名称。子类的其它属性,像普通类一样,定义在subclass标签的内部。
实体类是:
public class CollectionMapping {
private int id;
private String name;
private Set setValue;
private List listValue;
private String[] arrayValue;
private Map mapValue;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set getSetValue() {
return setValue;
}
public void setSetValue(Set setValue) {
this.setValue = setValue;
}
public List getListValue() {
return listValue;
}
public void setListValue(List listValue) {
this.listValue = listValue;
}
public String[] getArrayValue() {
return arrayValue;
}
public void setArrayValue(String[] arrayValue) {
this.arrayValue = arrayValue;
}
public Map getMapValue() {
return mapValue;
}
public void setMapValue(Map mapValue) {
this.mapValue = mapValue;
}
}
在CollectionMapping.hbm.xml文件中:
<hibernate-mapping>
<class name="CollectionMapping" table="t_CollectionMapping">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<set name="setValue" table="t_set_value">
<key column="set_id"/>
<element type="string" column="set_value"/>
</set>
<list name="listValue" table="t_list_value">
<key column="list_id"/>
<list-index column="list_index"/>
<element type="string" column="list_value"/>
</list>
<array name="arrayValue" table="t_array_value">
<key column="array_id"/>
<list-index column="array_index"/>
<element type="string" column="array_value"/>
</array>
<map name="mapValue" table="t_map_value">
<key column="map_id"/>
<map-key type="string" column="map_key"/>
<element type="string" column="map_value"/>
</map>
</class>
</hibernate-mapping>
在数据库中生成5个表
例如:
普通类:
public class Contact {
private String email;
private String address;
private String zipCode;
private String contactTel;
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getZipCode() {
return zipCode;
}
public void setZipCode(String zipCode) {
this.zipCode = zipCode;
}
public String getContactTel() {
return contactTel;
}
public void setContactTel(String contactTel) {
this.contactTel = contactTel;
}
}
实体类:
public class User {
private int id;
private String name;
private Contact contact;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Contact getContact() {
return contact;
}
public void setContact(Contact contact) {
this.contact = contact;
}
}
User.hbm.xml文件:
<hibernate-mapping>
<class name="User" table="t_user">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<component name="contact">
<property name="email"/>
<property name="address"/>
<property name="zipCode"/>
<property name="contactTel"/>
</component>
</class>
</hibernate-mapping>
在数据库中在t_user表中含有Contact类的属性字段
<id name="id" column="user_id" length="32">
<!-- 主键自动生成uuid -->
<generator class="uuid"/>
</id>
<id name="id" column="user_id">
<!-- 主键自动增长 -->
<generator class="native"/>
</id>
<id name="id" column="user_id" length="32">
<!-- 主键需要手动定义 -->
<generator class="assigned"/>
</id>
1.先导入dom4j-1.6.1.jar包
2.xml文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<config>
<action name="user" className="com.kaishengit.web.UserAction">
<result name="success" type="forward">suc.jsp</result>
<result name="error" type="redirect">404.jsp</result>
</action>
<action name="book" className="com.kaishengit.web.BookAction">
<result name="success">book.jsp</result>
<result name="error" type="redirect">bookerror.jsp</result>
</action>
<action name="person" className="com.kaishengit.web.PersonAction" method="del">
<result name="ok">suc.jsp</result>
</action>
</config>
3.解析测试类是:
package com.kaishengit.test;
import java.io.File;
import java.net.URL;
import java.util.List;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
public class Dom4jTest {
public void readXML() {
//拿到src文件夹里的xml配置文件
URL url = getClass().getResource("/");
System.out.println(url);
String filePath = url.getFile() + "struts.xml";
try {
//创建读取配置文件的对象
SAXReader reader = new SAXReader();
//开始读取配置文件
Document doc = reader.read(new File(filePath));
//拿到根节点
Element root = doc.getRootElement();
//拿到根节点下的action接点数组
List<Element> actions = root.elements("action");
for(Element action : actions) {
String name = action.attributeValue("name");
String className = action.attributeValue("className");
String method = action.attributeValue("method");
System.out.println("name="+name);
System.out.println("className="+className);
System.out.println("method="+method);
List<Element> results = action.elements("result");
for(Element result : results) {
String resultName = result.attributeValue("name");
String resultType = result.attributeValue("type");
String pageName = result.getText();
System.out.println("name:" + resultName + "\tresultType:" + resultType + "\tpageName:" + pageName);
}
System.out.println("----------------------");
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Dom4jTest d = new Dom4jTest();
d.readXML();
}
}
现在写一个用状态模式实现的根据上班时间状态变化而行为变化的小程序,当时间<12上午上班时间,
<13午休时间,<17下午上班时间,<21加班时间,根据时间不同,条用的类方法不同。
状态模式适用于当对象的状态改变时,行为也改变,就可以使用状态模式
状态接口:
public interface State {
void writeProgram(Work work);
}
不同的实现类:
public class AfterNoonState implements State {
@Override
public void writeProgram(Work work) {
if(work.getHour()<17){
System.out.println("工作");
}else {
work.setCurrent(new EveningState());
work.writeProgram();
}
}
}
public class EveningState implements State {
@Override
public void writeProgram(Work work) {
if(work.isFinish()){
work.setCurrent(new RestState());
work.writeProgram();
}else {
if(work.getHour()<21){
System.out.println("加班");
}else {
work.setCurrent(new SleepState());
work.writeProgram();
}
}
}
}
public class ForenoonState implements State {
@Override
public void writeProgram(Work work) {
if(work.getHour()<12){
System.out.println("工作时间");
}else {
work.setCurrent(new NoonState());
work.writeProgram();
}
}
}
public class NoonState implements State {
@Override
public void writeProgram(Work work) {
if(work.getHour()<13){
System.out.println("午睡");
}else {
work.setCurrent(new AfterNoonState());
work.writeProgram();
}
}
}
public class RestState implements State {
@Override
public void writeProgram(Work work) {
System.out.println("回家");
}
}
public class SleepState implements State {
@Override
public void writeProgram(Work work) {
System.out.println("睡觉");
}
}
调用状态的类:
public class Work {
private State current;
public Work(double hour,boolean finish){
current = new ForenoonState();
this.hour = hour;
this.finish = finish;
}
private double hour;
public double getHour() {
return hour;
}
public State getCurrent() {
return current;
}
public void setCurrent(State current) {
this.current = current;
}
private boolean finish;
public boolean isFinish() {
return finish;
}
public void writeProgram(){
current.writeProgram(this);
}
}
测试类:
public class Test {
public static void main(String[] args) {
Work work = new Work(20, true);
work.writeProgram();
}
}
这是表数据
SELECT * FROM t_user WHERE username IS NULL;查询到id=8的数据
SELECT * FROM t_user WHERE username IS NOT NULL;查询到id=11,12,13,14的四条数据
SELECT * FROM t_user WHERE username ='';查询到id=11,12,13的三条数据
SELECT * FROM t_user WHERE username ='aa';查询到id=14的数据
get和load方法都是是利用对象的主键得到对象,并可以使对象处于持久态。
load方法获取对象时不会立即执行查询操作,而是在第一次使用对象是再去执行查询操作。如果查询的对象在数据库中不存在,load方法返回值不会为null,在第一次使用时抛出org.hibernate.ObjectNotFoundException异常。
使用get方法获取对象时会立即执行查询操作,并且对象在数据库中不存在时返回null值。
所以我们在实际使用中多使用get方法,这样我们可以先判断得到的对象是否是null,再操作
1.在配置文件中的配置:
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver" />
<property name="jdbcUrl" value="jdbc:mysql:///struts" />
<property name="properties">
<props>
<prop key="user">root</prop>
<prop key="password">root</prop>
</props>
</property>
</bean>
<bean id="simpleJdbcTemplate" class="org.springframework.jdbc.core.simple.SimpleJdbcTemplate">
<constructor-arg ref="dataSource"></constructor-arg>
</bean>
<bean id="userSimpleJdbcTemplateDao" class="com.yjw.dao.UserSimpleJdbcTemplateDao">
<property name="simpleJdbcTemplate" ref="simpleJdbcTemplate"></property>
</bean>
2.dao中的写法:
package com.yjw.dao;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
import com.yjw.bean.User;
public class UserSimpleJdbcTemplateDao {
private SimpleJdbcTemplate simpleJdbcTemplate;
public void setSimpleJdbcTemplate(SimpleJdbcTemplate simpleJdbcTemplate) {
this.simpleJdbcTemplate = simpleJdbcTemplate;
}
public void save(User user){
String sql = "INSERT INTO t_user (username,PASSWORD) VALUES (?,?)";
simpleJdbcTemplate.update(sql, user.getUsername(),user.getPassword());
}
public void update(User user){
String sql = "UPDATE t_user SET username=:username ,PASSWORD=:password WHERE id=:id?";
simpleJdbcTemplate.update(sql, user.getUsername(),user.getPassword(),user.getId());
}
public void delete(int id){
String sql = "delete from t_user where id=?";
simpleJdbcTemplate.update(sql, id);
}
private class UserRowmapper implements RowMapper<User> {
public User mapRow(ResultSet rs, int rowNum) throws SQLException {
User u = new User();
u.setId(rs.getInt("id"));
u.setUsername(rs.getString("username"));
u.setPassword(rs.getString("password"));
return u;
}
}
public User getUser(int id) {
String sql = "select id,username,password from t_user where id=?";
User user = simpleJdbcTemplate.queryForObject(sql, new UserRowmapper(), id);
return user;
}
public List<User> getList(){
String sql = "select id,username,password from t_user ";
List<User> list = simpleJdbcTemplate.query(sql, new UserRowmapper() );
return list;
}
}
四种通知的执行地方:前置通知
try{
业务代码
后置通知
} catch{
异常通知
} finally{
最终通知
}
1.需要的jar包:aspectjrt.jar,aspectjweaver.jar,cglib-nodep-2.1.3.jar
2.在配置文件中加入
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
">
<bean id="myXmlAspect" class="com.yjw.aspect.MyXmlAspect"/>
<!-- 配置事务切面-->
<aop:config>
<aop:aspect ref="myXmlAspect">
<aop:pointcut expression="execution(* com.yjw.dao..*.*(..))" id="pointcut"/>
<aop:before method="beforeAdvice" pointcut-ref="pointcut"/>
<aop:after-returning method="afterReturningAdvice" returning="value" pointcut-ref="pointcut"/>
<aop:after-throwing method="exceptionAdvice" pointcut-ref="pointcut" throwing="ex"/>
<aop:after method="afterAdvice" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
</beans>
package com.yjw.aspect;
public class MyXmlAspect {
//前置通知
public void beforeAdvice(){
System.out.println("前置通知");
}
//异常通知,接收异常信息
public void exceptionAdvice(Exception ex){
System.out.println("异常出现"+ex.getMessage());
}
//后置通知,可以接收方法的返回值
public void afterReturningAdvice(Object value){
System.out.println("后置通知"+value);
}
//最终通知
public void afterAdvice(){
System.out.println("after");
}
}
查询集合
String sql = "select id, address,userid from t_address where userid in(select id from t_user where id in (select id from t_card where cardnum=112))";
SQLQuery query = session.createSQLQuery(sql).addEntity(Address.class);
List list = session.createSQLQuery(sql).list();
for(Object a : list){
Object[] address = (Object[]) a;
System.out.println(address[0]+" "+address[1]+" "+address[2]);
}
查询一个对象
String sql = "select id,username,password from t_user where id in (select id from t_card where cardnum=112)";
SQLQuery query = session.createSQLQuery(sql).addEntity(User.class);
User user = (User) query.uniqueResult();
System.out.println(user.getPwd());
单例就是在系统运行中只有一个实例对象
public class Factory {
private static Factory factory = new Factory();
private Factory(){
System.out.println("--");
}
public static Factory getFactory(){
return factory;
}
public void say(){
System.out.println("say");
}
}
第二种
public class Factory {
private static Factory factory =null;
private Factory(){
System.out.println("--");
}
public synchronized static Factory getFactory(){
if(factory==null){
factory = new Factory();
}
return factory;
}
public void say(){
System.out.println("say");
}
}
将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
例子,让羊的叫声和狼一样,羊就是一个适配器:
public class Wolf {
public void run() {
System.out.println("wolf run");
}
public void ho() {
System.out.println("wolf ho");
}
}
适配器接口:
public interface Sheep {
public void run();
public void ho();
}
实现类:
public class SheepAdapter implements Sheep{
private Wolf wolf;
public SheepAdapter(Wolf wolf) {
this.wolf = wolf;
}
@Override
public void run() {
wolf.run();
}
@Override
public void ho() {
wolf.ho();
}
}
测试类:
public static void main(String[] args) {
Wolf w = new Wolf();
Sheep sa = new SheepAdapter(w);
sa.run();
sa.ho();
}
}
动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更为灵活。
例子:
被装饰的接口:
public interface Cake {
public float cost();
}
接口的实现类:
public class MilkCake implements Cake{
@Override
public float cost() {
return 100f;
}
}
装饰者抽象类:
public abstract class CakeDecorator implements Cake{
}
装饰者的实现类
public class Chocolate extends CakeDecorator{
private Cake cake;
public Chocolate(Cake cake) {
this.cake = cake;
}
@Override
public float cost() {
float chocolatePrice = 25f;
return cake.cost() + chocolatePrice;
}
}
public class Berry extends CakeDecorator {
private Cake cake;
public Berry(Cake cake) {
this.cake = cake;
}
@Override
public float cost() {
float berryPrice = 5f;
return cake.cost() + berryPrice;
}
}
测试类:
public class Test {
public static void main(String[] args) {
MilkCake mc = new MilkCake();//牛奶蛋糕
System.out.println(mc.cost());
Berry b = new Berry(mc);//牛奶草莓蛋糕
System.out.println(b.cost());
Chocolate c = new Chocolate(b);//牛奶草莓巧克力蛋糕
System.out.println("付款:" + c.cost());
}
}
为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
1.当你要为一个复杂子系统提供一个简单接口时。子系统往往因为不断演化而变得越来越 复杂。大多数模式使用时都会产生更多更小的类。这使得子系统更具可重用性,也更容 易对子系统进行定制,但这也给那些不需要定制子系统的用户带来一些使用上的困难。 Facade可以提供一个简单的缺省视图,这一视图对大多数用户来说已经足够,而那些需 要更多的可定制性的用户可以越过facade层。
2.客户程序与抽象类的实现部分之间存在着很大的依赖性。引入facade将这个子系统与客 户以及其他的子系统分离,可以提高子系统的独立性和可移植性。
3.当你需要构建一个层次结构的子系统时,使用facade模式定义子系统中每层的入口点。 如果子系统之间是相互依赖的,你可以让它们仅通过facade进行通讯,从而简化了它们 之间的依赖关系。
例子:
外观类:
public class Facade {
ServiceA sa;
ServiceB sb;
ServiceC sc;
public Facade() {
sa = new ServiceAImpl();
sb = new ServiceBImpl();
sc = new ServiceCImpl();
}
public void methodA() {
sa.methodA();
sb.methodB();
}
public void methodB() {
sb.methodB();
sc.methodC();
}
public void methodC() {
sc.methodC();
sa.methodA();
}
}
接口和接口的实现类:
public interface ServiceA {
void methodA() ;
}
public class ServiceAImpl implements ServiceA{
@Override
public void methodA() {
System.out.println("这是服务A");
}
}
public interface ServiceB {
void methodB() ;
}
public class ServiceBImpl implements ServiceB{
@Override
public void methodB() {
System.out.println("这是服务B");
}
}
public interface ServiceC {
void methodC() ;
}
public class ServiceCImpl implements ServiceC{
@Override
public void methodC() {
System.out.println("这是服务C");
}
}
测试类:
public class Test {
public static void main(String[] args) {
ServiceA sa = new ServiceAImpl();
ServiceB sb = new ServiceBImpl();
sa.methodA();
sb.methodB();
System.out.println("========");
//facade
Facade facade = new Facade();
facade.methodA();
facade.methodB();
facade.methodC();
}
}
运用共享技术有效地支持大量细粒度的对象。
1.一次性实现一个算法的不变的部分,并将可变的行为留给子类来实现。
2.各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复。 首先识别现有代码中的不同之处,并且将不同之处分离为新的操作。 最后,用一个调用这些新的操作的模板方法来替换这些不同的代码。
3.控制子类扩展。
例子;
享元接口:
public interface Flyweight {
void action(int arg);
}
享元接口的实现类:
public class FlyweightImpl implements Flyweight{
@Override
public void action(int arg) {
System.out.println("参数值: " + arg);
}
}
产生精度对象的工厂类:
public class FlyweightFactory {
private static Map<String,Flyweight> flyweightsMap = new HashMap<String,Flyweight>();
public FlyweightFactory(String arg) {
System.out.println("-----------------");
flyweightsMap.put(arg, new FlyweightImpl());
}
public static Flyweight getFlyweight(String key) {
if (flyweightsMap.get(key) == null) {
flyweightsMap.put(key, new FlyweightImpl());
}
return (Flyweight) flyweightsMap.get(key);
}
public static int getSize() {
return flyweightsMap.size();
}
}
测试类:
public class Test {
public static void main(String[] args) {
Flyweight fly1 = FlyweightFactory.getFlyweight("a");
fly1.action(1);
Flyweight fly2 = FlyweightFactory.getFlyweight("a");
System.out.println(fly1 == fly2);
Flyweight fly3 = FlyweightFactory.getFlyweight("c");
fly3.action(3);
Flyweight fly4 = FlyweightFactory.getFlyweight("d");
fly4.action(4);
Flyweight fly5 = FlyweightFactory.getFlyweight("e");
fly5.action(5);
System.out.println(FlyweightFactory.getSize());
}
}
代理模式实现了类与类之间直接调用的解耦,例子:
代理模式主要使用了java的多态,干活的是被代理类,代理类主要的接活
,把活交给幕后的被代理类做,代理类和被代理类实现同一个接口。
被代理类的接口:
public interface Object {
void action();
}
被代理类的接口实现类:
public class ObjectImpl implements Object{
public void action() {
System.out.println("========");
System.out.println("========");
System.out.println("这是被代理的类");
System.out.println("========");
System.out.println("========");
}
}
代理类:
public class ProxyObject implements Object{
Object obj;
public ProxyObject() {
System.out.println("这是代理类");
obj = new ObjectImpl();
}
public void action() {
System.out.println("代理开始");
obj.action();
System.out.println("代理结束");
}
}
测试类:
public class Test {
public static void main(String[] args) {
Object obj = new ProxyObject();
obj.action();
}
}
定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。
适合场合:
* 1.以不同的格式保存文件
* 2.以不同的算法压缩文件
* 3.以不同的算法截取图形
* 4.以不同的格式输出数据的图形,曲线,框图等
策略接口:
public interface Strategy {
void method();
}
策略接口实现类:
public class StrategyImplA implements Strategy{
public void method() {
System.out.println("这是第一个实现a");
}
}
public class StrategyImplB implements Strategy{
public void method() {
System.out.println("这是第二个实现b");
}
}
public class StrategyImplC implements Strategy{
public void method() {
System.out.println("这是第三个实现c");
}
}
调用类:
public class Context {
Strategy stra;
public Context(Strategy stra) {
this.stra = stra;
}
public void doMethod() {
stra.method();
}
}
测试:
public class Test {
public static void main(String[] args) {
Context ctx = new Context(new StrategyImplA());
ctx.doMethod();
ctx = new Context(new StrategyImplB());
ctx.doMethod();
ctx = new Context(new StrategyImplC());
ctx.doMethod();
}
}
命令模式就是将一组对象的相似行为,进行了抽象,将调用者与被调用者之间进行解耦,提
高了应用的灵活性。命令模式将调用的目标对象的一些异构性给封装起来,通过统一的方式来为调用者提供服务。
适用场景
1、当一个应用程序调用者与多个目标对象之间存在调用关系时,并且目标对象之间的操作很类似的时候。
2、例如当一个目标对象内部的方法调用太复杂,或者内部的方法需要协作才能完成对象的某个特点操作时。
3、有时候调用者调用目标对象后,需要回调一些方法。
例子:
命令接口:
public interface Commond {
public void execute();
}
命令接口实现类:
public class LightOnCommond implements Commond{
private Light light;
public LightOnCommond(Light light) {
this.light = light;
}
@Override
public void execute() {
light.on();
}
}
命令的调用者:
public class Light {
public void on() {
System.out.println("灯亮了");
}
}
public class TurnTvCommond implements Commond {
private Tv tv;
public TurnTvCommond(Tv tv) {
this.tv = tv;
}
@Override
public void execute() {
tv.turn();
}
}
public class Tv {
public void turn() {
System.out.println("调台");
}
}
同时执行的多个命令数组
public class MracoCommond implements Commond{
private Commond[] commonds;
public MracoCommond(Commond...commonds) {
this.commonds = commonds;
}
@Override
public void execute() {
for(Commond cmd : commonds) {
cmd.execute();
}
}
}
命令的包装类,
public class RemoteContro {
private List<Commond> commondList = new ArrayList<Commond>();
public void setCommond(Commond commond) {
commondList.add(commond);
}
public void buttonWasPressed(int index){
commondList.get(index-1).execute();
}
}
public class Test {
public static void main(String[] args) {
Light light = new Light();
LightOnCommond loc = new LightOnCommond(light);
Tv tv = new Tv();
TurnTvCommond ttc = new TurnTvCommond(tv);
MracoCommond mc = new MracoCommond(loc,ttc);
RemoteContro rc = new RemoteContro();
rc.setCommond(ttc);
rc.setCommond(loc);
rc.setCommond(mc);
//rc.buttonWasPressed(3);
//rc.buttonWasPressed(1);
rc.buttonWasPressed(2);
}
}
当输入123不同时,调用的命令不同,实现了多个命令的包装
1.把依赖类(Service)和被依赖类(Dao)全部交给Spring管理
2.依赖类中提供被依赖类的set方法
3.在xml中进行配置
当把一个类交给spring管理是要给出一个无参数的构造方法给spring使用
<bean id="person" class="com.yjw.bean.Person1" factory-method="getPerson1" scope="prototype">
</bean>
scope="prototype"是创建多例,不配置此项,默认单例
或者lazy-init值设置为true
public class Person1 implements Person{
private Person1(String s){
System.out.println(s);
}
public void say() {
System.out.println("00000000000000");
}
public static Person1 getPerson1(){
return new Person1("pppppppppp");
}
}
<bean id="person" class="com.yjw.bean.Person1" factory-method="getPerson1">
public class Test {
public static void main(String[] args) {
ApplicationContext ctx =new ClassPathXmlApplicationContext("applicationContext.xml");
// UserService userservice =(UserService) ctx.getBean("person");
/* User u = new User();
u.setUsername("qq");
u.setPassword("qq");
userservice.save(u);*/
Person person = (Person) ctx.getBean("person");
person.say();
}
}
概述:
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
适用性:
1.当一个抽象模型有两个方面,其中一个方面依赖于另一方面。 将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。 2.当对一个对象的改变需要同时改变其它对象,而不知道具体有多少对象有待改变。 3.当一个对象必须通知其它对象,而它又不能假定其它对象是谁。
我们以天气预报的服务为例,安卓和诺基亚购买天气预报的服务,也可以停用服务:
天气预报主体的接口:
public interface Subject {
public void zhuce(Observer observer);
public void remove(Observer observer);
public void tongzhi();
}
天气预报的实现类:
public class WeatherData implements Subject {
private int low;
private int hight;
private String weather;
private List<Observer> list = new ArrayList<Observer>();
public void setData(int low, int hight, String weather) {
this.low = low;
this.hight = hight;
this.weather = weather;
tongzhi();
}
public int getLow() {
return low;
}
public int getHight() {
return hight;
}
public String getWeather() {
return weather;
}
public void zhuce(Observer observer) {
if (!list.contains(observer)) {
list.add(observer);
}
}
public void remove(Observer observer) {
if (list.contains(observer)) {
list.remove(observer);
}
}
public void tongzhi() {
for (Observer o : list) {
o.update(getLow(), getHight(), getWeather());
}
}
}
观察者的接口:
public interface Observer {
void remove();
void update(int low, int hight, String weather);
}
观察者的实现类:
public class Android implements Observer {
private Subject subject;
public Android() {
}
public Android(Subject subject) {
this.subject = subject;
this.subject.zhuce(this);
}
public void update(int low, int hight, String weather) {
System.out.println("android" + low + "" + hight + weather);
}
public void remove() {
subject.remove(this);
}
}
public class Nokia implements Observer{
private Subject subject;
public Nokia(){}
public Nokia(Subject subject){
this.subject = subject;
this.subject.zhuce(this);
}
public void update(int low, int hight, String weather) {
System.out.println("nokia:"+low+"-"+hight+"-"+weather);
}
public void remove(){
subject.remove(this);
}
}
测试类:
public class Test {
public static void main(String[] args) {
WeatherData wd = new WeatherData();
wd.setData(1, 22, "晴朗");
Android a = new Android(wd);
wd.tongzhi();
a.remove();
Nokia n = new Nokia(wd);
n.remove();
wd.tongzhi();
}
}
状态模式
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
用性:1.一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为。
2.一个操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态。
这个状态通常用一个或多个枚举常量表示。
通常,有多个操作包含这一相同的条件结构。
State模式将每一个条件分支放入一个独立的类中。
这使得你可以根据对象自身的情况将对象的状态作为一个对象,这一对象可以不依赖于其他对象而独立变化。
状态模式在工作流或游戏等各种系统中有大量使用,甚至是这些系统的核心功能设计,例如
政府OA中,一个批文的状态有多种:未办;正在办理;正在批示;正在审核;已经完成等
各种状态,使用状态机可以封装这个状态的变化规则,从而达到扩充状态时,不必涉及到状
态的使用者。
在网络游戏中,一个游戏活动存在开始;开玩;正在玩;输赢等各种状态,使用状态模式就
可以实现游戏状态的总控,而游戏状态决定了游戏的各个方面,使用状态模式可以对整个游
戏架构功能实现起到决定的主导作用。
状态模式实质:
使用状态模式前,客户端外界需要介入改变状态,而状态改变的实现是琐碎或复杂的。
使用状态模式后,客户端外界可以直接使用事件Event实现,根本不必关心该事件导致如
何状态变化,这些是由状态机等内部实现。
这是一种Event-condition-State,状态模式封装了condition-State部分。
每个状态形成一个子类,每个状态只关心它的下一个可能状态,从而无形中形成了状态转换
的规则。如果新的状态加入,只涉及它的前一个状态修改和定义。
状态转换有几个方法实现:一个在每个状态实现next(),指定下一个状态;还有一种方法,
设定一个StateOwner,在StateOwner设定stateEnter状态进入和stateExit状
态退出行为。
状态从一个方面说明了流程,流程是随时间而改变,状态是截取流程某个时间片。
例子:
操作当前状态类:
public class Context {
private Weather weather;
public void setWeather(Weather weather) {
this.weather = weather;
}
public Weather getWeather() {
return this.weather;
}
public String weatherMessage() {
return weather.getWeather();
}
}
状态接口:
public interface Weather {
String getWeather();
}
状态实现类:
public class Sunshine implements Weather{
public String getWeather() {
return "阳光";
}
}
public class Rain implements Weather{
public String getWeather() {
return "下雨";
}
}
测试类:
public class Test {
public static void main(String[] args) {
Context ctx1 = new Context();
ctx1.setWeather(new Sunshine());
System.out.println(ctx1.weatherMessage());
System.out.println("===============");
ctx1.setWeather(new Rain());
System.out.println(ctx1.weatherMessage());
}
}
例子2:
public class Work {
private State current;
public Work(double hour,boolean finish){
current = new ForenoonState();
this.hour = hour;
this.finish = finish;
}
private double hour;
public double getHour() {
return hour;
}
public State getCurrent() {
return current;
}
public void setCurrent(State current) {
this.current = current;
}
private boolean finish;
public boolean isFinish() {
return finish;
}
public void writeProgram(){
current.writeProgram(this);
}
}
public interface State {
void writeProgram(Work work);
}
public class ForenoonState implements State {
@Override
public void writeProgram(Work work) {
if(work.getHour()<12){
System.out.println("工作时间");
}else {
work.setCurrent(new NoonState());
work.writeProgram();
}
}
}
public class NoonState implements State {
@Override
public void writeProgram(Work work) {
if(work.getHour()<13){
System.out.println("午睡");
}else {
work.setCurrent(new AfterNoonState());
work.writeProgram();
}
}
}
public class AfterNoonState implements State {
@Override
public void writeProgram(Work work) {
if(work.getHour()<17){
System.out.println("工作");
}else {
work.setCurrent(new EveningState());
work.writeProgram();
}
}
}
public class EveningState implements State {
@Override
public void writeProgram(Work work) {
if(work.isFinish()){
work.setCurrent(new RestState());
work.writeProgram();
}else {
if(work.getHour()<21){
System.out.println("加班");
}else {
work.setCurrent(new SleepState());
work.writeProgram();
}
}
}
}
public class SleepState implements State {
@Override
public void writeProgram(Work work) {
System.out.println("睡觉");
}
}
访问者模式主要是将很多操作都在一个接口中声明,在接口的实现类中都要实现这些操作,
在具体的访问者类中规定了需要调用实现类的哪个方法,
例子如下:
访问者接口:
public interface Visitor {
public void visitString(StringElement stringE);
public void visitFloat(FloatElement floatE);
public void visitCollection(Collection<?> collection);
public void visitInt(IntElement inte);
}
访问者接口实现类
public class ConcreteVisitor implements Visitor{
public void visitCollection(Collection<?> collection) {
Iterator<?> iterator = collection.iterator();
while (iterator.hasNext()) {
Object o = iterator.next();
if (o instanceof Visitable) {
((Visitable)o).accept(this);
}
}
}
public void visitFloat(FloatElement floatE) {
System.out.println(floatE.getFe());
}
public void visitString(StringElement stringE) {
System.out.println(stringE.getSe());
}
@Override
public void visitInt(IntElement inte) {
System.out.println(inte.getInts());
}
}
操作类的接口:
public interface Visitable {
public void accept(Visitor visitor);
}
操作类的具体实现类:
public class FloatElement implements Visitable{
private Float fe;
public FloatElement(Float fe) {
this.fe = fe;
}
public Float getFe() {
return this.fe;
}
public void accept(Visitor visitor) {
visitor.visitFloat(this);
}
}
public class IntElement implements Visitable{
private int ints;
public int getInts() {
return ints;
}
public IntElement(int i){
this.ints = i;
}
@Override
public void accept(Visitor visitor) {
visitor.visitInt(this);
}
}
public class StringElement implements Visitable{
private String se;
public StringElement(String se) {
this.se = se;
}
public String getSe() {
return this.se;
}
public void accept(Visitor visitor) {
visitor.visitString(this);
}
}
测试类:
public class Test {
public static void main(String[] args) {
Visitor visitor = new ConcreteVisitor();
Visitable se = new StringElement("abc");
se.accept(visitor);
Visitable fe = new FloatElement(new Float(1.5));
fe.accept(visitor);
System.out.println("===========");
List<Visitable> result = new ArrayList<Visitable>();
result.add(new StringElement("abc"));
result.add(new StringElement("abc"));
result.add(new StringElement("abc"));
result.add(new FloatElement(new Float(1.5)));
result.add(new FloatElement(new Float(1.5)));
result.add(new FloatElement(new Float(1.5)));
visitor.visitCollection(result);
Visitable is = new IntElement(2);
is.accept(visitor);
}
}
概述:
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。
TemplateMethod使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
适用性:
1.一次性实现一个算法的不变的部分,并将可变的行为留给子类来实现。
2.各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复。
首先识别现有代码中的不同之处,并且将不同之处分离为新的操作。
最后,用一个调用这些新的操作的模板方法来替换这些不同的代码。
例子如下:模板类:
public abstract class Template {
public abstract void print();
public void update() {
System.out.println("公共的代码");
System.out.println("下面是子类各自实现的代码");
print();
}
}
模板类的子类:
public class TemplateConcrete extends Template{
@Override
public void print() {
System.out.println("这是子类的实现");
}
}
测试类
public class Test {
public static void main(String[] args) {
Template temp = new TemplateConcrete();
temp.update();
}
}
grid.addListener('cellclick', cellclick);
function cellclick(grid, rowIndex, columnIndex, e) {
var record = grid.getStore().getAt(rowIndex);
var fieldName = grid.getColumnModel().getDataIndex(columnIndex);
var data = record.get(fieldName);
if(data==null){ //处理预览
var alias=record.get("Alias");
window.open(url);
//window.location.href="DoIpcammera?dowith=preview&&alias="+alias;
}
}
new Ext.grid.RowNumberer()
var AddtoobarT = new Ext.form.Radio({
name : "istoobar",//后台接受的名称
inputValue : "true",//传后台的值
boxLabel : "有",//页面显示的值
checked : true//默认选择的值
});
var AddtoobarF = new Ext.form.Radio({
name : "istoobar",
inputValue : "false",
boxLabel : "没有"
});
var Addtoobar = new Ext.form.RadioGroup({
name : "toolbar",
fieldLabel : "有无工具栏",
items : [ AddtoobarT, AddtoobarF ],
width : 200
});
职责链模式规定了一个请求,这个请求需要特定的对象去处理,当把这个请求交个一个对象,但是这个对象不负责处理这个请求,可以动态地交给其他对象处理,直到交给对的对象处理,这些对象都有处理请求的机会,只有当请求是该自己负责的时候才处理,否则交给其他对象。
下面以==============
要离职, 人事审批!
请求完毕
===========
要加薪, 项目经理审批!
========
要请假, 项目组长审批!
的规定,写一个职责链模式的例子:
这是所有请求的接口
public interface Request {
void getRequest();
}
请假的请求实现类
public class LeaveRequest implements Request{
@Override
public void getRequest() {
System.out.println("leave");
}
}
离职的请求实现类
public class DimissionRequest implements Request{
@Override
public void getRequest() {
System.out.println("dimission");
}
}
加薪的请求实现类
public class AddMoneyRequest implements Request{
@Override
public void getRequest() {
System.out.println("add money");
}
}
处理请求的接口
public interface RequestHandle {
void handleRequest(Request request);
}
Hr处理离职的请求
public class HRRequestHandle implements RequestHandle{
public void handleRequest(Request request) {
if (request instanceof DimissionRequest) {
System.out.println("要离职, 人事审批!");
}
System.out.println("请求完毕");
}
}
组长处理请假的请求
public class TLRequestHandle implements RequestHandle{
RequestHandle rh;
public TLRequestHandle(RequestHandle rh) {
this.rh = rh;
}
public void handleRequest(Request request) {
if (request instanceof LeaveRequest) {
System.out.println("要请假, 项目组长审批!");
} else {
rh.handleRequest(request);
}
}
}
经理处理加薪的请求
public class PMRequestHandle implements RequestHandle{
RequestHandle rh;
public PMRequestHandle(RequestHandle rh) {
this.rh = rh;
}
public void handleRequest(Request request) {
if (request instanceof AddMoneyRequest) {
System.out.println("要加薪, 项目经理审批!");
} else {
rh.handleRequest(request);
}
}
}
测试类
public class Test {
public static void main(String[] args) {
//先把所有的处理请求的对象组成职责链
RequestHandle hr = new HRRequestHandle();
RequestHandle tl = new TLRequestHandle(hr);//组长
RequestHandle pm = new PMRequestHandle(tl);//经理
Request dimissionRequest = new DimissionRequest();
Request addMoneyRequest = new AddMoneyRequest();
Request leaveRequest = new LeaveRequest();
System.out.println("==============");
//人事处理离职请求
pm.handleRequest(dimissionRequest);
System.out.println("===========");
//经理处理加薪请求
pm.handleRequest(addMoneyRequest);
System.out.println("========");
//项目组长处理请假请求
pm.handleRequest(leaveRequest);
}
}
在使用时要调用最高级的职责调用者,由他去负责往下分配职责
is null是判断某个字段是否是空,为空并不等价于空字符串或者数字0
=null 是判断某个值是否等于null,null=null,和null<>null都是false
select DISTINCT job from emp where deptno=20
select name from user where upper(name) ='TOM' and sal is not null;
upper()函数的作用是把表中的name转换成大写再做比较
求薪金sal列和绩效comm列的和,comm可能是空,
select sal+if(comm is null,0,comm) from emp;
当comm是空时,返回0,不空时返回comm的数值
public class User implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private String name;
public User(){
System.out.println("===============");
}
public User(String name){
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "user="+this.name;
}
}
<s:property value="new User('name')"/>
public class Test {
public static String NAME = "nametom";
public static String test(){
return "testtom";
}
}
在struts.xml配置文件中加<constant name="struts.ognl.allowStaticMethodAccess" value="true"></constant>
<s:property value="@Test@test()"/>
<s:property value="@Test@NAME"/>
public class UserAction extends ActionSupport{
/**
*
*/
private static final long serialVersionUID = 1L;
public String mm(){
return "mm";
}
}
<s:property value="mm()"/>
public class User implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private String name;
public User(){
System.out.println("===============");
}
public User(String name){
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "user="+this.name;
}
}
public class UserAction extends ActionSupport{
/**
*
*/
private static final long serialVersionUID = 1L;
private String name;
private User user;
private Cat cat;
@Override
public String execute() throws Exception {
// System.out.println(cat.getFriend().getName());
return ActionSupport.SUCCESS;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Cat getCat() {
return cat;
}
public void setCat(Cat cat) {
this.cat = cat;
}
}
<s:property value="user.toString()"/>
public class User implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private String name;
public User(){
System.out.println("========空的构造方法=必须有======");
}
public User(String name){
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class UserAction extends ActionSupport{
/**
*
*/
private static final long serialVersionUID = 1L;
private String name;
private User user;
@Override
public String execute() throws Exception {
System.out.println(user.getName());
return ActionSupport.SUCCESS;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
<body>
<s:form action="user/tologin.action" method="post">
<s:textarea name="id"></s:textarea>
<s:password name="user.password"></s:password>
<s:textfield name="user.name" label="ddddd" > </s:textfield>
<s:submit value="提交" method="login"></s:submit>
<s:submit value="打印" method="print"></s:submit>
</s:form>
</body>
验证框架的命名规则是Action类名字-action的bean名字-validation.xml,这个验证文件需要放在需要验证的.class文件同一目录下
例如UserAction-tologin-validation.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC
"-//Apache Struts//XWork Validator 1.0.2//EN"
"http://struts.apache.org/dtds/xwork-validator-1.0.2.dtd">
<validators>
<field name="id">
<field-validator type="int">
<param name="min">10</param>
<param name="max">20</param>
<message>必须是整数</message>
</field-validator>
</field>
<field name="user.name">
<field-validator type="requiredstring">
<message>name必须填写</message>
</field-validator>
</field>
</validators>
在struts-xml中的配置
<action name="tologin" class="UserAction" >
<result>/WEB-INF/user/list.jsp</result>
<result name="input">/WEB-INF/user/user.jsp</result>
</action>
<body>
<s:form action="user/tologin.action" method="post">
<s:textarea name="id"></s:textarea>
<s:password name="user.password"></s:password>
<s:textfield name="user.name"></s:textfield>
<s:submit value="提交" method="login"></s:submit>
<s:submit value="打印" method="print"></s:submit>
</s:form>
</body>
<action name="tologin" class="UserAction" >
<result>/WEB-INF/user/list.jsp</result>
</action>
public class UserAction extends ActionSupport{
private static final long serialVersionUID = 1L;
private User user;
private String id;
@Override
public String execute() throws Exception {
return ActionSupport.SUCCESS;
}
public String login(){
return ActionSupport.SUCCESS;
}
public String print(){
System.out.println(user.getName());
System.out.println(user.getPassword());
System.out.println(id);
return ActionSupport.SUCCESS;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
<a href="hello?name=1">重定向传参数</a>
<package name="default" namespace="/" extends="struts-default">
<default-action-ref name="hello"></default-action-ref>
<action name="hello" class="UserAction">
<result type="redirect">/index2.jsp?t=${name}</result>
</action>
</package>
public class UserAction extends ActionSupport{
/**
*
*/
private static final long serialVersionUID = 1L;
private String name;
@Override
public String execute() throws Exception {
System.out.println(name);
return ActionSupport.SUCCESS;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
<s:property value="#parameters.t"/>
第一种
public class UserAction extends ActionSupport{
/**
*
*/
private static final long serialVersionUID = 1L;
private String name;
private Map session;
private Map request;
private Map application;
@Override
public String execute() throws Exception {
session = ActionContext.getContext().getSession();
request = (Map) ActionContext.getContext().get("request");
application = ActionContext.getContext().getApplication();
session.put("sk", "sv");
request.put("rk", "rv");
application.put("ak", "av");
System.out.println(name);
return ActionSupport.SUCCESS;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
第二种
public class DepAction extends ActionSupport implements RequestAware,SessionAware,ApplicationAware{
private Map<String, Object> request;
private Map<String, Object> session;
private Map<String, Object> application;
public void setRequest(Map<String, Object> request) {
this.request = request;
}
public void setSession(Map<String, Object> session) {
this.session = session;
}
public void setApplication(Map<String, Object> application) {
this.application = application;
}
}
第三种
public class CarAction implements ServletRequestAware{
private HttpServletRequest request;
private HttpSession session;
private ServletContext application;
public void setServletRequest(HttpServletRequest request) {
this.request = request;
this.session = request.getSession();
this.application = session.getServletContext();
}
}
第四种
public class HomeAction extends ActionSupport{
private HttpServletRequest request;
private HttpSession session;
private ServletContext application;
public HomeAction (){
request = ServletActionContext.getRequest();
session = request.getSession();
application = session.getServletContext();
}
}
摘要: Struts2常用标签总结
一 介绍
1.Struts2的作用
Struts2标签库提供了主题、模板支持,极大地简化了视图页面的编写,而且,struts2的主题、模板都提供了很好的扩展性。实现了更好的代码复用。Struts2允许在页面中使用自定义组件,这完全能满足项目中页面显示复杂,多变的需求。
Struts2的标签库有一个巨大的改进之处,struts2标签库的标签不依赖于任何...
阅读全文
在strut2中所以的值都在值栈中存放,在页面中加入<s:debug></s:debug>标签,就可以点击显示出当前值栈中的所有值,如图
可以通过 <s:property value="name"/>标签得到值栈中的值,value的值是PropertyName,就可以得到对应的value
在action中session,request,application都是Map数据类型的
private Map session;
private Map request;
private Map application;
session = ActionContext.getContext().getSession();
request = (Map) ActionContext.getContext().get("request");
application = ActionContext.getContext().getApplication();
session.put("sk", "sv");
request.put("rk", "rv");
application.put("ak", "av");
想在页面中取到相应的值;
<s:property value="#session.sk"/>
<s:property value="#request.rk"/>
<s:property value="#application.ak"/>
使用<s:debug></s:debug>观看他们都是存放在栈区,#+名称就可以取到值
namespace决定来了action的访问路径,当namespace=“”时,可以接受所有路径的action,namespace=“/”,
或者"/xxx,或者"/xxx/yyy",对应的action访问路径是/index.action,或者/xxx/index.action,或
者/xxx/yyy/index.action.
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort
()+path+"/";
%>
<base href="<%=basePath%>">
在使用namespace时容易出现路径问题,在会出现路径问题的jsp页面中加上base标签,就不会了。
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
public class Test {
public static void main(String[] args) {
Calendar calendar = Calendar.getInstance();
calendar.setFirstDayOfWeek(Calendar.MONDAY);
calendar.add(Calendar.DATE, -7);
calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
Date sTime = calendar.getTime();
calendar.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
Date eTime = calendar.getTime();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String s = sdf.format(sTime) + " 00:00:00";
String e = sdf.format(eTime) + " 23:59:59";
System.out.println(s);
System.out.println(e);
}
}
摘要: 在struts2中的拦截器的定义是先定义一个类实现Interceptor接口,重写intercept方法。下面是实现登录验证的拦截器。 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts C...
阅读全文
Typeof()返回值有6中可能:number,string,boolean,object,function,undefined
Prompt(“请输入名称”)返回字符
eval(“”)可以把“”中的字符串执行
在java中继承的构造方法的规则:
1. 子类的构造的过程中必须调用其父类的构造方法。
2. 子类可以在自己的构造方法中使用super(argument—list)调用父类的构造方法。
3. 使用this(argument—list)调用自己的另外的构造方法。
4. 如果调用super,必须卸载子类构造方法的第一行。
5. 如果子类的构造方法中没有显示调用父类工作服,系统默认调用父类无参数的构造方法。
6. 如果子类构造方法中没有显示调用父类的构造方法,而父类中又没有无参数的构造方法,编译出错。
哈希编码:每个对象都有一个独一无二的哈希编码,通过这个哈希编码可以找到这个对象。
多态中动态绑定规则;1.有继承,2.有重写(子类重写父类中的方法),3.父类引用指向子类对象。
Public void getId(final int i){}表示i在此方法中不同被修改
<!--?启动时删数据库中的表,然后创建,退出时不删除数据表
<property?name="hibernate.hbm2ddl.auto">create</property>-->
<!--?启动时删数据库中的表,然后创建,退出时自动删除所有表
<property?name="hibernate.hbm2ddl.auto">create-drop</property>-->
<!--?自动修改,如果表结构与实体类不一致,那么就修改表使它们一致,数据会保留
<property?name="hibernate.hbm2ddl.auto">update</property>-->
<!--?自动校验,如果表结构与实体类不一致,那么不做任何操作,报错
<property?name="hibernate.hbm2ddl.auto">validate</property>-->
public class ReadSql {
public static void readsql(String filePath) throws Exception{
String encoding = "gbk";
File file = new File(filePath);
if(file.isFile()&&file.exists()){
InputStreamReader reader = new InputStreamReader(new FileInputStream(file),encoding);
BufferedReader bufferedReader = new BufferedReader(reader);
String line = null;
while ((line = bufferedReader.readLine())!=null) {
System.out.println(line.toString());
}
reader.close();
}
}
public static void main(String[] args) throws Exception {
System.out.println("=================================================");
ReadSql.readsql("c:/rr.txt");
System.out.println("=================================================");
}
}
阿里云服务平台注册相当于申请到了一台服务器主机,想运行java web项目很简单,安装jdk,tomcat,数据库,把编译好的项目放在tomcat中,启动tomcat,在外网直接访问阿里云主机ip和端口,项目名称,就可以了
在网络编程中,先启动service,再启动clent。
1.tcp
服务端
public class Service {
public static void main(String[] args) throws Exception {
ServerSocket ss = new ServerSocket(6666);
System.out.println("等待");
while (true) {
Socket socket =ss.accept();
InputStream is = socket.getInputStream();
DataInputStream dataInputStream = new DataInputStream(is);
System.out.println(dataInputStream.readUTF());
dataInputStream.close();
socket.close();
}
}
}
客户端
public class CientSocket {
public static void main(String[] args) throws Exception {
Socket socket = new Socket("127.0.0.1",6666);
OutputStream outputStream = socket.getOutputStream();
DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
dataOutputStream.writeUTF("333333333");
dataOutputStream.flush();
dataOutputStream.close();
socket.close();
}
}
udp通信,是不区分客户端和服务端的
public class Service {
public static void main(String[] args) throws Exception {
byte buf[] = new byte[1024];
DatagramPacket dPacket = new DatagramPacket(buf, buf.length);
DatagramSocket dSocket = new DatagramSocket(5678);
while (true) {
dSocket.receive(dPacket);
System.out.println(new String(buf,0,dPacket.getLength()));
}
}
}
public class UdpClient {
public static void main(String[] args) throws Exception{
while (true) {
byte[] buf = (new String("hello")).getBytes();
DatagramPacket dpPacket = new DatagramPacket(buf, buf.length, new InetSocketAddress("127.0.0.1", 5678));
//自己占用9999端口
DatagramSocket dSocket = new DatagramSocket(9999);
dSocket.send(dpPacket);
dSocket.close();
}
}
}
当我们去启动一个 WEB 项目的时候, 容器(包括 JBoss, Tomcat 等)首先会去读项目的 web.xml 配置文件里面的信息,
当这一步骤没有出错并且完成之后, 项目才能正常的被启动起来。
1> 首先是, 容器会先读 <context-param></context-param> 节点, 并创建一个 ServletContext 实例, 以节点的 name 作为键, value 作为值,
存储到上下文环境中。
2> 接着, 容器会去读 <listener></listener> 节点, 根据配置的 class 类路径来创建监听。
3> 接着, 容器去读 <filter></filter> 节点, 根据指定的类路径来实例化过滤器。
以上都是在 WEB 项目还没有完全启动起来的时候就已经完成了的工作。如果系统中有用到 Servlet, 则 Servlet 是在第一次发起请求的时候被实例化的,
且一般不会被容器销毁, 它可以服务于多个用户的请求。所以, Servlet 的初始化都要比上面提到的那几个要迟。
总的来说, web.xml 的加载顺序是: context-param --> listener --> filter --> servlet
其中, 如果 web.xml 中出现了相同的节点, 则是按照在配置文件中出现的先后顺序来加载的。
下面引入一个小列子来说明:
<?xml version="1.0" encoding="UTF-8"?>
<listener>
<listener-class>net.yeah.fancydeepin.listener.AppStartListener</listener-class>
</listener>
<!-- 为了更好的说明, 特意将 context-param 放在 listener 后面 -->
<context-param>
<param-name>technology</param-name>
<param-value>java,javascript,ajax,css,html</param-value>
</context-param>
<filter>
<filter-name>ReDespatcherFilter</filter-name>
<filter-class>net.yeah.fancydeepin.filter.ReDespatcherFilter</filter-class>
<init-param>
<param-name>it</param-name>
<param-value>android, python, c</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>ReDespatcherFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>ReDespatcherFilter2</filter-name>
<filter-class>net.yeah.fancydeepin.filter.ReDespatcherFilter2</filter-class>
<init-param>
<param-name>mail</param-name>
<param-value>fancydeepin@yeah.net</param-value>
</init-param>
</filter>
</web-app>
package net.yeah.fancydeepin.listener;
import java.util.Arrays;
import java.util.List;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class AppStartListener implements ServletContextListener{
public void contextInitialized(ServletContextEvent contextEvent) {
System.out.println("********************************************");
ServletContext context = contextEvent.getServletContext();
List<String> params = Arrays.asList(context.getInitParameter("technology").split(","));
for(String param : params){
System.out.print(param + "\t");
}
System.out.println("\n********************************************");
}
public void contextDestroyed(ServletContextEvent contextEvent) {
}
}
package net.yeah.fancydeepin.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class ReDespatcherFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("============================================");
System.out.println(filterConfig.getInitParameter("it"));
System.out.println("============================================");
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,ServletException{
chain.doFilter(request, response);
}
public void destroy() {
}
}
package net.yeah.fancydeepin.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class ReDespatcherFilter2 implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("++++++++++++++++++++++++++++++++++++++++++++");
System.out.println(filterConfig.getInitParameter("mail"));
System.out.println("++++++++++++++++++++++++++++++++++++++++++++");
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,ServletException{
chain.doFilter(request, response);
}
public void destroy() {
}
}
后台启动输出结果:
在 java 中, 常见的 Context 有很多,
像: ServletContext, ActionContext, ServletActionContext, ApplicationContext, PageContext, SessionContext ...
那么, Context 究竟是什么东西呢? 直译是上下文、环境的意思。比如像: "今天我收到了一束花, 男朋友送的!" 又或者 "今天我收到了一束花, 送花的人送错了的!"
同样是收到一束花, 在不同的上下文环境中表达的意义是不一样的。
同样的, Context 其实也是一样, 它离不开所在的上下文环境, 否则就是断章取义了。
另外, 在网络上也有些人把 Context 看成是一些公用信息或者把它看做是一个容器的, 个人觉得这种解释稍好。
接下来说说 ServletContext, ActionContext, ServletActionContext。
1> ServletContext
一个 WEB 运用程序只有一个 ServletContext 实例, 它是在容器(包括 JBoss, Tomcat 等)完全启动 WEB 项目之前被创建, 生命周期伴随整个 WEB 运用。
当在编写一个 Servlet 类的时候, 首先是要去继承一个抽象类 HttpServlet, 然后可以直接通过 getServletContext() 方法来获得 ServletContext 对象。
这是因为 HttpServlet 类中实现了 ServletConfig 接口, 而 ServletConfig 接口中维护了一个 ServletContext 的对象的引用。
利用 ServletContext 能够获得 WEB 运用的配置信息, 实现在多个 Servlet 之间共享数据等。
eg:
<?xml version="1.0" encoding="UTF-8"?>
<context-param>
<param-name>url</param-name>
<param-value>jdbc:oracle:thin:@localhost:1521:ORC</param-value>
</context-param>
<context-param>
<param-name>username</param-name>
<param-value>scott</param-value>
</context-param>
<context-param>
<param-name>password</param-name>
<param-value>tigger</param-value>
</context-param>
<servlet>
<servlet-name>ConnectionServlet</servlet-name>
<servlet-class>net.yeah.fancydeepin.servlet.ConnectionServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ConnectionServlet</servlet-name>
<url-pattern>/ConnectionServlet.action</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>PrepareConnectionServlet</servlet-name>
<servlet-class>net.yeah.fancydeepin.servlet.PrepareConnectionServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>PrepareConnectionServlet</servlet-name>
<url-pattern>/PrepareConnectionServlet.action</url-pattern>
</servlet-mapping>
</web-app>
package net.yeah.fancydeepin.servlet;
import java.io.IOException;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class PrepareConnectionServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public void init() throws ServletException {
ServletContext context = getServletContext();
String url = context.getInitParameter("url");
String username = context.getInitParameter("username");
String password = context.getInitParameter("password");
context.setAttribute("url", url);
context.setAttribute("username", username);
context.setAttribute("password", password);
}
protected void doGet(HttpServletRequest request,HttpServletResponse response)throws ServletException,IOException{
doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.sendRedirect("ConnectionServlet.action");
}
}
package net.yeah.fancydeepin.servlet;
import java.io.IOException;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
public class ConnectionServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
ServletContext context = getServletContext();
System.out.println("***************************************");
System.out.println("URL: " + context.getAttribute("url"));
System.out.println("Username: " + context.getAttribute("username"));
System.out.println("Password: " + context.getAttribute("password"));
System.out.println("***************************************");
super.service(request, response);
}
}
当访问 PrepareConnectionServlet.action 时, 后台打印输出:
***********************************************
URL: jdbc:oracle:thin:@localhost:1521:ORC
Username: scott
Password: tigger
***********************************************
2> ActionContext
ActionContext 是当前 Action 执行时的上下文环境, ActionContext 中维护了一些与当前 Action 相关的对象的引用,
如: Parameters (参数), Session (会话), ValueStack (值栈), Locale (本地化信息) 等。
在 Struts1 时期, Struts1 的 Action 与 Servlet API 和 JSP 技术的耦合度都很紧密, 属于一个侵入式框架:
public ActionForward execute(ActionMapping mapping,ActionForm form,HttpServletRequest request,HttpServletResponse response){
// TODO Auto-generated method stub
return null;
}
到了 Struts2 时期, Struts2 的体系结构与 Struts1 之间存在很大的不同。Struts2 在 Struts1 的基础上与 WebWork 进行了整合, 成为了一个全新的框架。
在 Struts2 里面, 则是通过 WebWork 来将与 Servlet 相关的数据信息转换成了与 Servlet API 无关的对象, 即 ActionContext 对象。
这样就使得了业务逻辑控制器能够与 Servlet API 分离开来。另外, 由于 Struts2 的 Action 是每一次用户请求都产生一个新的实例, 因此,
ActionContext 不存在线程安全问题, 可以放心使用。
package net.yeah.fancydeepin.action;
import java.util.Map;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.util.ValueStack;
public class ContextAction extends ActionSupport {
private static final long serialVersionUID = 1L;
private String username;
private String password;
public String execute(){
ActionContext context = ActionContext.getContext();
ValueStack value = context.getValueStack();
value.set("username", username);
value.set("password", password);
Map<String, Object> session = context.getSession();
session.put("url", "http://www.blogjava.net/fancydeepin");
return SUCCESS;
}
public void setUsername(String username) {
this.username = username;
}
public void setPassword(String password) {
this.password = password;
}
}
<s:property value="username"/><BR>
<s:property value="password"/><BR>
<s:property value="#session.url"/><BR>
当访问 context.action 并传给相应的参数的时候, 在浏览器中会输出相应的信息。
留意到上面 Struts2 的 Action 中并有没添加属性的 getting 方法, 而是手动的将参数值放到值栈(ValueStack)中的, 否则页面是得不到参数来输出的。
3> ServletActionContext
首先, ServletActionContext 是 ActionContext 的一个子类。ServletActionContext 从名字上来看, 意味着它与 Servlet API 紧密耦合。
ServletActionContext 的构造子是私有的, 主要是提供了一些静态的方法, 可以用来获取: ActionContext, ActionMapping, PageContext,
HttpServletRequest, HttpServletResponse, ServletContext, ValueStack, HttpSession 对象的引用。
public String execute(){
//或 implements ServletRequestAware
HttpServletRequest request = ServletActionContext.getRequest();
//或 implements ServletResponseAware
HttpServletResponse response = ServletActionContext.getResponse();
//或 implements SessionAware
HttpSession session = request.getSession();
//或 implements ServletContextAware
ServletContext context = ServletActionContext.getServletContext();
return SUCCESS;
}
public static int method(int n){
if(n==1){
return 1;
}else {
return n*method(n-1);
}
}
public static long fab(int i){
if(i==1||i==2){
return 1;
}else {
return fab(i-1)+fab(i-2);
}
}
1.先把编辑好的web文件放在c盘下,比如项目名是hello
2.打开cmd,进入hello中,c:\hello>
3.输入jar cvf hello.war . ,就可以在hello文件夹中找到hello.war
输入jar -cvf hello.jar *.*;
DATE_FORMAT() 函数用于以不同的格式显示日期/时间数据。
语法是
date 参数是合法的日期。format 规定日期/时间的输出格式。
下面的脚本使用 DATE_FORMAT() 函数来显示不同的格式。我们使用 NOW() 来获得当前的日期/时间:
DATE_FORMAT(NOW(),'%b %d %Y %h:%i %p') DATE_FORMAT(NOW(),'%m-%d-%Y') DATE_FORMAT(NOW(),'%d %b %y') DATE_FORMAT(NOW(),'%d %b %Y %T:%f')
结果类似:
Dec 29 2008 11:45 PM 12-29-2008 29 Dec 08 29 Dec 2008 16:25:46.635
当数据库中有个字段time,数据格式是
2013-03-25 14:35:20
按年查询:
DATE_FORMAT(timetext,'%Y')=‘2013’
按年排序
DATE_FORMAT(timetext,'%Y')
按月查询
DATE_FORMAT(timetext,'%m')='03
'
这个问题是说,你不能在对一个List进行遍历的时候将其中的元素删除掉
解决办法是,你可以先将要删除的元素用另一个list装起来,等遍历结束再remove掉
可以这样写
List delList = new ArrayList();//用来装需要删除的元素
for(Information ia:list)
if(ia.getId()==k){
n++;
delList.add(ia);
}
list.removeAll(delList);//遍历完成后执行删除
package com.test;
/**
* 动态生成随机字符数组
*
*
*/
public class ShortMessageCodeUntil
{
/**
* 随机生成4位数字字符数组
*
* @return rands
*/
public static char[] generateCheckCode()
{
String chars = "0123456789";
char[] rands = new char[4];
for (int i = 0; i < 4; i++)
{
int rand = (int) (Math.random() * 10);
rands[i] = chars.charAt(rand);
}
return rands;
}
/**
* 随机生成6位数字字符数组
*
* @return rands
*/
public static char[] generateCheckPass()
{
String chars = "0123456789";
char[] rands = new char[6];
for (int i = 0; i < 6; i++)
{
int rand = (int) (Math.random() * 10);
rands[i] = chars.charAt(rand);
}
return rands;
}
public static void main(String[] args) {
ShortMessageCodeUntil sm = new ShortMessageCodeUntil();
System.out.println(sm.generateCheckCode());
System.out.println(sm.generateCheckPass());
}
}
<div><a href="javascript:void(0)" class="aa" rel="<%=k %>">点击</a></div>
<script type="text/javascript">
$(document).ready(function(){
$(".aa").click(function(){
var id = $(this).attr("rel");
$.get('<%=basePath%>wenshi/setDaPeng', {
p :id
}, function(r,s) {
});
});
});
</script>
Builder模式定义: 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示.
Builder模式是一步一步创建一个复杂的对象,它允许用户可以只通过指定复杂对象的类型和内容就可以构建它们.
用户不知道内部的具体构建细节.Builder模式是非常类似抽象工厂模式,细微的区别大概只有在反复使用中才能体会到.
为何使用? 是为了将构建复杂对象的过程和它的部件解耦.注意: 是解耦过程和部件.
因为一个复杂的对象,不但有很多大量组成部分,如汽车,有很多部件:车轮方向盘 发动机还有各种小零件等等,
部件很多,但远不止这些,如何将这些部件装配成一辆汽车,这个装配过程也很复杂(需要很好的组装技术),Builder模式就是为了将部件和组装过程分开.
如何使用? 首先假设一个复杂对象是由多个部件组成的,Builder模式是把复杂对象的创建和部件的创建分别开来,分别用Builder类和Director类来表示.
首先,需要一个接口,它定义如何创建复杂对象的各个部件:
public interface Builder {
//创建部件A 比如创建汽车车轮
void buildPartA();
//创建部件B 比如创建汽车方向盘
void buildPartB();
//创建部件C 比如创建汽车发动机
void buildPartC();
//返回最后组装成品结果 (返回最后装配好的汽车)
//成品的组装过程不在这里进行,而是转移到下面的Director类中进行. //从而实现了解耦过程和部件
Product getResult();
}
用Director构建最后的复杂对象,而在上面Builder接口中封装的是如何创建一个个部件(复杂对象是由这些部件组成的),也就是说Director的内容是如何将部件最后组装成成品:
public class Director {
private Builder builder;
public Director( Builder builder ) {
this.builder = builder;
} // 将部件partA partB partC最后组成复杂对象 //这里是将车轮方向盘和发动机组装成汽车的过程
public void construct() {
builder.buildPartA();
builder.buildPartB();
builder.buildPartC();
}
}
Builder的具体实现ConcreteBuilder: 通过具体完成接口Builder来构建或装配产品的部件;
定义并明确它所要创建的是什么具体东西; 提供一个可以重新获取产品的接口:
public class ConcreteBuilder implements Builder {
Part partA, partB, partC; public void buildPartA() {
//这里是具体如何构建partA的代码 };
public void buildPartB() {
//这里是具体如何构建partB的代码 };
public void buildPartC() {
//这里是具体如何构建partB的代码 };
public Product getResult() { //返回最后组装成品结果 };
复杂对象:产品Product:
public interface Product { }
复杂对象的部件:
public interface Part { }
我们看看如何调用Builder模式:
ConcreteBuilder builder = new ConcreteBuilder();
Director director = new Director( builder );
director.construct();
Product product = builder.getResult();
}
Builder模式的应用在Java实际使用中,我们经常用到"池"(Pool)的概念,当资源提供者无法提供足够的资源,并且这些资源需要被很多用户反复共享时,就需要使用池.
"池"实际是一段内存,当池中有一些复杂的资源的"断肢"(比如数据库的连接池,也许有时一个连接会中断),如果循环再利用这些"断肢",将提高内存使用效率,提高池的性能.修改Builder模式中Director类使之能诊断"断肢"断在哪个部件上,再修复这个部件.
单态定义: Singleton模式主要作用是保证在Java应用程序中,一个类Class只有一个实例存在。
在很多操作中,比如建立目录 数据库连接都需要这样的单线程操作。
还有, singleton能够被状态化; 这样,多个单态类在一起就可以作为一个状态仓库一样向外提供服务,比如,你要论坛中的帖子计数器,每次浏览一次需要计数,单态类能否保持住这个计数,并且能synchronize的安全自动加1,如果你要把这个数字永久保存到数据库,你可以在不修改单态接口的情况下方便的做到。
另外方面,Singleton也能够被无状态化。提供工具性质的功能, Singleton模式就为我们提供了这样实现的可能。使用Singleton的好处还在于可以节省内存,因为它限制了实例的个数,有利于Java垃圾回收(garbage collection)。我们常常看到工厂模式中类装入器(class loader)中也用Singleton模式实现的,因为被装入的类实际也属于资源。
public class Singleton {
private Singleton(){}
//在自己内部定义自己一个实例,是不是很奇怪? //注意这是private 只供内部调用
private static Singleton instance = new Singleton();
//这里提供了一个供外部访问本class的静态方法,可以直接访问
public static Singleton getInstance() {
return instance;
}
}
第二种形式:
public class Singleton {
private Singleton(){}
private static Singleton instance = null;
public static synchronized Singleton getInstance() {
//这个方法比上面有所改进,不用每次都进行生成对象,只是第一次 //使用时生成实例,提高了效率!
if (instance==null)
instance=new Singleton();
return instance;
}
}
使用Singleton.getInstance()可以访问单态类。
上面第二中形式是lazy initialization,也就是说第一次调用时初始Singleton,以后就不用再生成了。
注意到lazy initialization形式中的synchronized,这个synchronized很重要,如果没有synchronized,那么使用getInstance()是有可能得到多个Singleton
实例。
一般认为第一种形式要更加安全些。
工厂模式定义:提供创建对象的接口
为什么工厂模式是如此常用?因为工厂模式就相当于创建实例对象的new,我们经常要根据类Class生成实例对象,如A a=new A() 工厂模式也是用来创建实例对象的,所以以后new时就要多个心眼,是否可以考虑实用工厂模式,虽然这样做,可能多做一些工作,但会给你系统带来更大的可扩展性和尽量少的修改量。
我们以类Sample为例, 如果我们要创建Sample的实例对象:
Sample sample=new Sample();
可是,实际情况是,通常我们都要在创建sample实例时做点初始化的工作,比如赋值查询数据库等。
首先,我们想到的是,可以使用Sample的构造函数,这样生成实例就写成:
Sample sample=new Sample(参数);
但是,如果创建sample实例时所做的初始化工作不是象赋值这样简单的事,可能是很长一段代码,如果也写入构造函数中,那你的代码很难看了(就需要Refactor重整)。
为什么说代码很难看,初学者可能没有这种感觉,我们分析如下,初始化工作如果是很长一段代码,说明要做的工作很多,将很多工作装入一个方法中,相当于将很多鸡蛋放在一个篮子里,是很危险的,这也是有背于Java面向对象的原则,面向对象的封装(Encapsulation)
和分派(Delegation)告诉我们,尽量将长的代码分派“切割”成每段,将每段再“封装”起来(减少段和段之间偶合联系性),这样,就会将风险分散,以后如果需要修改,只要更改每段,不会再发生牵一动百的事情。
在本例中,首先,我们需要将创建实例的工作与使用实例的工作分开, 也就是说,让创建实例所需要的大量初始化工作从Sample的构造函数中分离出去。
这时我们就需要Factory工厂模式来生成对象了,不能再用上面简单new Sample(参数)。还有,如果Sample有个继承如MySample, 按照面向接口编程,我们需要将Sample抽象成一个接口.现在Sample是接口,有两个子类MySample 和HisSample .我们要实例化他们时,如下:
Sample mysample=new MySample(); Sample hissample=new HisSample();
随着项目的深入,Sample可能还会"生出很多儿子出来", 那么我们要对这些儿子一个个实例化,更糟糕的是,可能还要对以前的代码进行修改:加入后来生出儿子的实例.这在传统程序中是无法避免的.
但如果你一开始就有意识使用了工厂模式,这些麻烦就没有了.
工厂方法你会建立一个专门生产Sample实例的工厂:
public class Factory{
public static Sample creator(int which){
//getClass 产生Sample 一般可使用动态类装载装入类。 if (which==1) return new SampleA(); else if (which==2)
return new SampleB();
}
}
那么在你的程序中,如果要实例化Sample时.就使用
Sample sampleA=Factory.creator(1);
这样,在整个就不涉及到Sample的具体子类,达到封装效果,也就减少错误修改的机会
使用工厂方法要注意几个角色,首先你要定义产品接口,如上面的Sample,产品接口下有Sample接口的实现类,如SampleA,其次要有一个factory类,用来生成产品Sample,
进一步稍微复杂一点,就是在工厂类上进行拓展,工厂类也有继承它的实现类concreteFactory了。
抽象工厂 工厂模式中有: 工厂方法(Factory Method) 抽象工厂(Abstract Factory).
这两个模式区别在于需要创建对象的复杂程度上。如果我们创建对象的方法变得复杂了,如上面工厂方法中是创建一个对象Sample,如果我们还有新的产品接口Sample2.
这里假设:Sample有两个concrete类SampleA和SamleB,而Sample2也有两个concrete类Sample2A和SampleB2
那么,我们就将上例中Factory变成抽象类,将共同部分封装在抽象类中,不同部分使用子类实现,下面就是将上例中的Factory拓展成抽象工厂:
public abstract class Factory{
public abstract Sample creator();
public abstract Sample2 creator(String name);
}
public class SimpleFactory extends Factory{
public Sample creator(){ ......... return new SampleA }
public Sample2 creator(String name){ ......... return new Sample2A }
}
public class BombFactory extends Factory{
public Sample creator(){ ...... return new SampleB }
public Sample2 creator(String name){ ...... return new Sample2B }
}
从上面看到两个工厂各自生产出一套Sample和Sample2,也许你会疑问,为什么我不可以使用两个工厂方法来分别生产Sample和Sample2?
抽象工厂还有另外一个关键要点,是因为 SimpleFactory内,生产Sample和生产Sample2的方法之间有一定联系,所以才要将这两个方法捆绑在一个类中,这个工厂类有其本身特征,也许制造过程是统一的,比如:制造工艺比较简单,所以名称叫SimpleFactory。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title></title>
<!-- 引入jQuery -->
<script src="../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script type="text/javascript" >
//<![CDATA[
$(function(){
var $div_li =$("div.tab_menu ul li");
$div_li.click(function(){
$(this).addClass("selected") //当前<li>元素高亮
.siblings().removeClass("selected"); //去掉其它同辈<li>元素的高亮
var index = $div_li.index(this); // 获取当前点击的<li>元素 在 全部li元素中的索引。
$("div.tab_box > div") //选取子节点。不选取子节点的话,会引起错误。如果里面还有div
.eq(index).show() //显示 <li>元素对应的<div>元素
.siblings().hide(); //隐藏其它几个同辈的<div>元素
}).hover(function(){
$(this).addClass("hover");
},function(){
$(this).removeClass("hover");
})
})
//]]>
</script>
</head>
<body>
<div class="tab">
<div class="tab_menu">
<ul>
<li class="selected">时事</li>
<li>体育</li>
<li>娱乐</li>
</ul>
</div>
<div class="tab_box">
<div>时事</div>
<div class="hide">体育</div>
<div class="hide">娱乐</div>
</div>
</div>
</body>
</html>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title></title>
<!-- 引入jQuery -->
<script src="../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){
$("span").click(function(){
var thisEle = $("#para").css("font-size");
var textFontSize = parseFloat(thisEle , 10);
var unit = thisEle.slice(-2); //获取单位
var cName = $(this).attr("class");
if(cName == "bigger"){
if( textFontSize <= 22 ){
textFontSize += 2;
}
}else if(cName == "smaller"){
if( textFontSize >= 12 ){
textFontSize -= 2;
}
}
$("#para").css("font-size", textFontSize + unit);
});
});
</script>
</head>
<body>
<div class="msg">
<div class="msg_caption">
<span class="bigger" >放大</span>
<span class="smaller" >缩小</span>
</div>
<div>
<p id="para">
This is some text. This is some text. This is some text. This is some text. This
is some text. This is some text. This is some text. This is some text. This is some
text. This is some text. This is some text. This is some text. This is some text.
This is some text. This is some text. This is some text. This is some text. This
is some text. This is some text.
</p>
</div>
</div>
</body>
</html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<script src="../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){
$("#filterName").keyup(function(){
$("table tbody tr")
.hide()
.filter(":contains('"+( $(this).val() )+"')")
.show();
}).keyup();
})
</script>
</head>
<body>
<div>
<br/>
筛选:
<input id="filterName" />
<br/>
</div>
<table>
<thead>
<tr><th>姓名</th><th>性别</th><th>暂住地</th></tr>
</thead>
<tbody>
<tr><td>张山</td><td>男</td><td>浙江宁波</td></tr>
<tr><td>李四</td><td>女</td><td>浙江杭州</td></tr>
<tr><td>王五</td><td>男</td><td>湖南长沙</td></tr>
<tr><td>找六</td><td>男</td><td>浙江温州</td></tr>
<tr><td>Rain</td><td>男</td><td>浙江杭州</td></tr>
<tr><td>MAXMAN</td><td>女</td><td>浙江杭州</td></tr>
<tr><td>王六</td><td>男</td><td>浙江杭州</td></tr>
<tr><td>李字</td><td>女</td><td>浙江杭州</td></tr>
<tr><td>李四</td><td>男</td><td>湖南长沙</td></tr>
</tbody>
</table>
</body>
</html>
<html>
<head>
<script src="../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){
$('tr.parent').click(function(){ // 获取所谓的父行
$(this)
.toggleClass("selected") // 添加/删除高亮
.siblings('.child_'+this.id).toggle(); // 隐藏/显示所谓的子行
}).click();
})
</script>
</head>
<body>
<table>
<thead>
<tr><th>姓名</th><th>性别</th><th>暂住地</th></tr>
</thead>
<tbody>
<tr class="parent" id="row_01"><td colspan="3">前台设计组</td></tr>
<tr class="child_row_01"><td>张山</td><td>男</td><td>浙江宁波</td></tr>
<tr class="child_row_01"><td>李四</td><td>女</td><td>浙江杭州</td></tr>
<tr class="parent" id="row_02"><td colspan="3">前台开发组</td></tr>
<tr class="child_row_02"><td>王五</td><td>男</td><td>湖南长沙</td></tr>
<tr class="child_row_02"><td>找六</td><td>男</td><td>浙江温州</td></tr>
<tr class="parent" id="row_03"><td colspan="3">后台开发组</td></tr>
<tr class="child_row_03"><td>Rain</td><td>男</td><td>浙江杭州</td></tr>
<tr class="child_row_03"><td>MAXMAN</td><td>女</td><td>浙江杭州</td></tr>
</tbody>
</table>
</body>
</html>
<html>
<head>
<script src="../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){
$("tbody>tr:odd").addClass("odd"); //先排除第一行,然后给奇数行添加样式
$("tbody>tr:even").addClass("even"); //先排除第一行,然后给偶数行添加样式
$('tbody>tr').click(function() {
if ($(this).hasClass('selected')) {
$(this)
.removeClass('selected')
.find(':checkbox').attr('checked',false);
}else{
$(this)
.addClass('selected')
.find(':checkbox').attr('checked',true);
}
});
// 如果复选框默认情况下是选择的,则高色.
// $('table :checkbox:checked').parent().parent().addClass('selected');
//简化:
$('table :checkbox:checked').parents("tr").addClass('selected');
//$('tbody>tr:has(:checked)').addClass('selected');
})
</script>
</head>
<body>
<table>
<thead>
<tr><th> </th><th>姓名</th><th>性别</th><th>暂住地</th></tr>
</thead>
<tbody>
<tr><td><input type="checkbox" name="choice" value=""/></td>
<td>张山</td><td>男</td><td>浙江宁波</td></tr>
<tr><td><input type="checkbox" name="choice" value="" /></td>
<td>李四</td><td>女</td><td>浙江杭州</td></tr>
<tr><td><input type="checkbox" name="choice" value="" checked='checked' /></td>
<td>王五</td><td>男</td><td>湖南长沙</td></tr>
<tr><td><input type="checkbox" name="choice" value="" /></td>
<td>找六</td><td>男</td><td>浙江温州</td></tr>
<tr><td><input type="checkbox" name="choice" value="" /></td>
<td>Rain</td><td>男</td><td>浙江杭州</td></tr>
<tr><td><input type="checkbox" name="choice" value="" /></td>
<td>MAXMAN</td><td>女</td><td>浙江杭州</td></tr>
</tbody>
</table>
</body>
</html>
<html>
<head>
<script src="../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){
$("tbody>tr:odd").addClass("odd");
$("tbody>tr:even").addClass("even");
$('tbody>tr').click(function() {
//判断当前是否选中
var hasSelected=$(this).hasClass('selected');
//如果选中,则移出selected类,否则就加上selected类
$(this)[hasSelected?"removeClass":"addClass"]('selected')
//查找内部的checkbox,设置对应的属性。
.find(':checkbox').attr('checked',!hasSelected);
});
// 如果复选框默认情况下是选择的,则高色.
$('tbody>tr:has(:checked)').addClass('selected');
})
</script>
</head>
<body>
<table>
<thead>
<tr><th> </th><th>姓名</th><th>性别</th><th>暂住地</th></tr>
</thead>
<tbody>
<tr><td><input type="checkbox" name="choice" value=""/></td>
<td>张山</td><td>男</td><td>浙江宁波</td></tr>
<tr><td><input type="checkbox" name="choice" value="" /></td>
<td>李四</td><td>女</td><td>浙江杭州</td></tr>
<tr><td><input type="checkbox" name="choice" value="" checked='checked' /></td>
<td>王五</td><td>男</td><td>湖南长沙</td></tr>
<tr><td><input type="checkbox" name="choice" value="" /></td>
<td>找六</td><td>男</td><td>浙江温州</td></tr>
<tr><td><input type="checkbox" name="choice" value="" /></td>
<td>Rain</td><td>男</td><td>浙江杭州</td></tr>
<tr><td><input type="checkbox" name="choice" value="" /></td>
<td>MAXMAN</td><td>女</td><td>浙江杭州</td></tr>
</tbody>
</table>
</body>
</html>
<html>
<head>
<script src="../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){
$("tbody>tr:odd").addClass("odd"); //先排除第一行,然后给奇数行添加样式
$("tbody>tr:even").addClass("even"); //先排除第一行,然后给偶数行添加样式
$('tbody>tr').click(function() {
$(this)
.addClass('selected')
.siblings().removeClass('selected')
.end()
.find(':radio').attr('checked',true);
});
// 如果单选框默认情况下是选择的,则高色.
// $('table :radio:checked').parent().parent().addClass('selected');
//简化:
$('table :radio:checked').parents("tr").addClass('selected');
//再简化:
//$('tbody>tr:has(:checked)').addClass('selected');
})
</script>
</head>
<body>
<table>
<thead>
<tr><th> </th><th>姓名</th><th>性别</th><th>暂住地</th></tr>
</thead>
<tbody>
<tr><td><input type="radio" name="choice" value=""/></td>
<td>张山</td><td>男</td><td>浙江宁波</td></tr>
<tr><td><input type="radio" name="choice" value="" /></td>
<td>李四</td><td>女</td><td>浙江杭州</td></tr>
<tr><td><input type="radio" name="choice" value="" checked='checked' /></td>
<td>王五</td><td>男</td><td>湖南长沙</td></tr>
<tr><td><input type="radio" name="choice" value="" /></td>
<td>找六</td><td>男</td><td>浙江温州</td></tr>
<tr><td><input type="radio" name="choice" value="" /></td>
<td>Rain</td><td>男</td><td>浙江杭州</td></tr>
<tr><td><input type="radio" name="choice" value="" /></td>
<td>MAXMAN</td><td>女</td><td>浙江杭州</td></tr>
</tbody>
</table>
</body>
</html>
<html>
<head>
<script src="../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){
//如果是必填的,则加红星标识.
$("form :input.required").each(function(){
var $required = $("<strong class='high'> *</strong>"); //创建元素
$(this).parent().append($required); //然后将它追加到文档中
});
//文本框失去焦点后
$('form :input').blur(function(){
var $parent = $(this).parent();
$parent.find(".formtips").remove();
//验证用户名
if( $(this).is('#username') ){
if( this.value=="" || this.value.length < 6 ){
var errorMsg = '请输入至少6位的用户名.';
$parent.append('<span class="formtips onError">'+errorMsg+'</span>');
}else{
var okMsg = '输入正确.';
$parent.append('<span class="formtips onSuccess">'+okMsg+'</span>');
}
}
//验证邮件
if( $(this).is('#email') ){
if( this.value=="" || ( this.value!="" && !/.+@.+\.[a-zA-Z]{2,4}$/.test(this.value) ) ){
var errorMsg = '请输入正确的E-Mail地址.';
$parent.append('<span class="formtips onError">'+errorMsg+'</span>');
}else{
var okMsg = '输入正确.';
$parent.append('<span class="formtips onSuccess">'+okMsg+'</span>');
}
}
}).keyup(function(){
$(this).triggerHandler("blur");
}).focus(function(){
$(this).triggerHandler("blur");
});//end blur
//提交,最终验证。
$('#send').click(function(){
$("form :input.required").trigger('blur');
var numError = $('form .onError').length;
if(numError){
return false;
}
alert("注册成功,密码已发到你的邮箱,请查收.");
});
//重置
$('#res').click(function(){
$(".formtips").remove();
});
})
</script>
</head>
<body>
<form method="post" action="">
<div class="int">
<label for="username">用户名:</label>
<input type="text" id="username" class="required" />
</div>
<div class="int">
<label for="email">邮箱:</label>
<input type="text" id="email" class="required" />
</div>
<div class="int">
<label for="personinfo">个人资料:</label>
<input type="text" id="personinfo" />
</div>
<div class="sub">
<input type="submit" value="提交" id="send"/><input type="reset" id="res"/>
</div>
</form>
</body>
</html>
<html>
<head>
<style type="text/css">
* { margin:0; padding:0; }
div.centent {
float:left;
text-align: center;
margin: 10px;
}
span {
display:block;
margin:2px 2px;
padding:4px 10px;
background:#898989;
cursor:pointer;
font-size:12px;
color:white;
}
</style>
<script src="../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){
//移到右边
$('#add').click(function() {
//获取选中的选项,删除并追加给对方
$('#select1 option:selected').appendTo('#select2');
});
//移到左边
$('#remove').click(function() {
$('#select2 option:selected').appendTo('#select1');
});
//全部移到右边
$('#add_all').click(function() {
//获取全部的选项,删除并追加给对方
$('#select1 option').appendTo('#select2');
});
//全部移到左边
$('#remove_all').click(function() {
$('#select2 option').appendTo('#select1');
});
//双击选项
$('#select1').dblclick(function(){ //绑定双击事件
//获取全部的选项,删除并追加给对方
$("option:selected",this).appendTo('#select2'); //追加给对方
});
//双击选项
$('#select2').dblclick(function(){
$("option:selected",this).appendTo('#select1');
});
$('#findall').click(function(){
var len= $('#select2 option').length;
for(var i=0;i<len;i++){
//$('#select2').get(i).value;
alert($('#select2 option')[i].value);
}
});
});
</script>
</head>
<body>
<div class="centent">
<select multiple="multiple" id="select1" style="width:100px;height:160px;">
<option value="1">选项1</option>
<option value="2">选项2</option>
<option value="3">选项3</option>
<option value="4">选项4</option>
<option value="5">选项5</option>
<option value="6">选项6</option>
<option value="7">选项7</option>
</select>
<div>
<span id="add" >选中添加到右边>></span>
<span id="add_all" >全部添加到右边>></span>
</div>
</div>
<div class="centent">
<select multiple="multiple" id="select2" style="width: 100px;height:160px;">
<option value="8">选项8</option>
</select>
<div>
<span id="remove"><<选中删除到左边</span>
<span id="remove_all"><<全部删除到左边</span>
<span id="findall"><<选中的所有值</span>
</div>
</div>
</body>
</html>
File f = new File("c://a.txt");
BufferedInputStream bis =new BufferedInputStream(new FileInputStream(f));
byte[] buffer = new byte[1024];
response.setContentType("application/octet-stream");
//定义下载文件的名字
String a = new String(z.getZiname().getBytes("utf-8"),"iso8859-1");
response.setHeader("Content-Disposition", "attachment; filename=\"" + a+"c://a.txt".substring("c://a.txt".lastIndexOf(".")) + "\"");
OutputStream os = response.getOutputStream();
int len = -1;
while((len=bis.read(buffer))!=-1){
os.write(buffer, 0, len);
}
os.flush();
os.close();
bis.close();
复选框 按钮
<html>
<head>
<script src="../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){
//全选
$("#CheckedAll").click(function(){
$('[name=items]:checkbox').attr('checked', true);
});
//全不选
$("#CheckedNo").click(function(){
$('[type=checkbox]:checkbox').attr('checked', false);
});
//反选
$("#CheckedRev").click(function(){
$('[name=items]:checkbox').each(function(){
//此处用JQ写法颇显啰嗦。体现不出JQ飘逸的感觉。
//$(this).attr("checked", !$(this).attr("checked"));
//直接使用JS原生代码,简单实用
this.checked=!this.checked;
});
});
//输出值
$("#send").click(function(){
var str="你选中的是:\r\n";
$('[name=items]:checkbox:checked').each(function(){
str+=$(this).val()+"\r\n";
})
alert(str);
});
})
</script>
</head>
<body>
<form method="post" action="">
你爱好的运动是?
<br/>
<input type="checkbox" name="items" value="足球"/>足球
<input type="checkbox" name="items" value="篮球"/>篮球
<input type="checkbox" name="items" value="羽毛球"/>羽毛球
<input type="checkbox" name="items" value="乒乓球"/>乒乓球
<br/>
<input type="button" id="CheckedAll" value="全 选"/>
<input type="button" id="CheckedNo" value="全不选"/>
<input type="button" id="CheckedRev" value="反 选"/>
<input type="button" id="send" value="提 交"/>
</form>
</body>
</html>
复选框
<html>
<head>
<script src="../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script>
$(function(){
//全选
$("#CheckedAll").click(function(){
if(this.checked){ //如果当前点击的多选框被选中
$('input[type=checkbox][name=items]').attr("checked", true );
}else{
$('input[type=checkbox][name=items]').attr("checked", false );
}
});
$('input[type=checkbox][name=items]').click(function(){
var flag=true;
$('input[type=checkbox][name=items]').each(function(){
if(!this.checked){
flag = false;
}
});
if( flag ){
$('#CheckedAll').attr('checked', true );
}else{
$('#CheckedAll').attr('checked', false );
}
});
//输出值
$("#send").click(function(){
var str="你选中的是:\r\n";
$('input[type=checkbox][name=items]:checked').each(function(){
str+=$(this).val()+"\r\n";
})
alert(str);
});
})
</script>
</head>
<body>
<form>
你爱好的运动是?<input type="checkbox" id="CheckedAll" />全选/全不选<br/>
<input type="checkbox" name="items" value="足球"/>足球
<input type="checkbox" name="items" value="篮球"/>篮球
<input type="checkbox" name="items" value="羽毛球"/>羽毛球
<input type="checkbox" name="items" value="乒乓球"/>乒乓球<br/>
<input type="button" id="send" value="提 交"/>
</form>
</body>
</html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script src="../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){
//全选
$("#CheckedAll").click(function(){
//所有checkbox跟着全选的checkbox走。
$('[name=items]:checkbox').attr("checked", this.checked );
});
$('[name=items]:checkbox').click(function(){
//定义一个临时变量,避免重复使用同一个选择器选择页面中的元素,提升程序效率。
var $tmp=$('[name=items]:checkbox');
//用filter方法筛选出选中的复选框。并直接给CheckedAll赋值。
$('#CheckedAll').attr('checked',$tmp.length==$tmp.filter(':checked').length);
/*
//一行做过多的事情需要写更多注释。复杂选择器还可能影响效率。因此不推荐如下写法。
$('#CheckedAll').attr('checked',!$('[name=items]:checkbox').filter(':not(:checked)').length);
*/
});
//输出值
$("#send").click(function(){
var str="你选中的是:\r\n";
$('[name=items]:checkbox:checked').each(function(){
str+=$(this).val()+"\r\n";
})
alert(str);
});
});
</script>
</head>
<body>
<form method="post" action="">
你爱好的运动是?<input type="checkbox" id="CheckedAll" />全选/全不选<br/>
<input type="checkbox" name="items" value="足球"/>足球
<input type="checkbox" name="items" value="篮球"/>篮球
<input type="checkbox" name="items" value="羽毛球"/>羽毛球
<input type="checkbox" name="items" value="乒乓球"/>乒乓球<br/>
<input type="button" id="send" value="提 交"/>
</form>
</body>
</html>
<html>
<head>
<style type="text/css">
body{
font:normal 12px/17px Arial;
}
div{
padding:2px;
}
input, textarea {
width: 12em;
border: 1px solid #888;
}
.focus {
border: 1px solid #f00;
background: #fcc;
}
</style>
<!-- 引入jQuery -->
<script src="../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){
$(":input").focus(function(){
$(this).addClass("focus");
if($(this).val() ==this.defaultValue){
$(this).val("");
}
}).blur(function(){
$(this).removeClass("focus");
if ($(this).val() == '') {
$(this).val(this.defaultValue);
}
});
})
</script>
</head>
<body>
<form action="" method="post" id="regForm">
<fieldset>
<legend>个人基本信息</legend>
<div>
<label for="username">名称:</label>
<input id="username" type="text" value="名称" />
</div>
<div>
<label for="pass">密码:</label>
<input id="pass" type="password" value="密码" />
</div>
<div>
<label for="msg">详细信息:</label>
<textarea id="msg" rows="2" cols="20">详细信息</textarea>
</div>
</fieldset>
</form>
</body>
</html>
先要导入jxl需要的jar包,然后在触发导出excel时传入集合对象,例如:
public class ToExcel {
public static void excel(List<WenShi> l,HttpServletResponse response) {
ServletOutputStream out = null;
WritableWorkbook wwb = null;
try {
// 导出Excel路径
Date d = new Date();
String s = new SimpleDateFormat("yyyyMMddHHmmss").format(d);
response.setCharacterEncoding("utf-8");
response.reset();
response.setContentType("application/vnd.ms-excel;charset=utf-8");
response.setHeader("Content-Disposition", "attachment;filename="
+ new String("历史数据.xls".getBytes(),"iso-8859-1"));
out = response.getOutputStream();
WritableSheet ws = null;
wwb = Workbook.createWorkbook(out);
ws = wwb.createSheet("sheet1", 0);
// 文字样式
WritableFont wf = new WritableFont(WritableFont.TIMES, 10,
WritableFont.BOLD, false);
WritableCellFormat wcff = new WritableCellFormat(wf);
// 标题
// 第一列第1行(0,0)
Label label1 = new Label(0, 0, "编号", wcff);
// 第一列第2行(0,1)
Label label2 = new Label(1, 0, "环境温度", wcff);
// 第一列第3行(0,2)
Label label3 = new Label(2, 0, "环境湿度", wcff);
Label label4 = new Label(3, 0, "光照强度", wcff);
Label label5 = new Label(4, 0, "土壤温度", wcff);
Label label6 = new Label(5, 0, "土壤湿度", wcff);
Label label7 = new Label(6, 0, "co2浓度", wcff);
// 第一列第4行(0,3)
Label label8 = new Label(7, 0, "时间", wcff);
// 第一列第5行(0,4)
Label label9 = new Label(8, 0, "星期几", wcff);
ws.addCell(label1);
ws.addCell(label2);
ws.addCell(label3);
ws.addCell(label4);
ws.addCell(label5);
ws.addCell(label6);
ws.addCell(label7);
ws.addCell(label8);
ws.addCell(label9);
for (int i = 0; i < l.size(); i++) {
Label l1 = new Label(0, i + 1, l.get(i).getStr("node"));
Label l2 = new Label(1, i + 1, l.get(i).getStr("wen"));
Label l3 = new Label(2, i + 1, l.get(i).getStr("shi"));
Label l4 = new Label(3, i + 1, l.get(i).getStr("sun"));
Label l5 = new Label(4, i + 1, l.get(i).getStr("tuwen"));
Label l6 = new Label(5, i + 1, l.get(i).getStr("tushi"));
Label l7 = new Label(6, i + 1, l.get(i).getStr("co"));
Label l8 = new Label(7, i + 1, l.get(i)
.getTimestamp("timetext").toString());
Label l9 = new Label(8, i + 1, l.get(i).getStr("week"));
ws.addCell(l1);
ws.addCell(l2);
ws.addCell(l3);
ws.addCell(l4);
ws.addCell(l5);
ws.addCell(l6);
ws.addCell(l7);
ws.addCell(l8);
ws.addCell(l9);
}
wwb.write();
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
wwb.close();
} catch (WriteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
onblur 事件 发生在窗口失去焦点的时候。应用于:window 对象
onchange 事件 发生在文本输入区的内容被更改,然 后焦点从文本输入区
移走之后。捕捉此事件主要用于实时检测输入的有效性,或者立刻改变文
档内容。应 用于:P assword 对象;S elect 对象;T ext 对象;T extarea 对
象
onclick 事件 发生在对象被单击的时候。单击是指鼠标停留在对象上,
按下鼠标键,没有移动鼠标而放开鼠标键这一个完整的过程。一个普通按
钮对象(Button)通常会有 onclick 事件处理程序,因为这种对象根本
不能从用户那里得到任何信息,没 有 onclick 事件处理程序就等于废柴。
按钮上添加 onclick 事件处理程序,可以模拟“另一个提交按钮”,方
法是:在事件处理程序中更改表单的 action, target, encoding, method
等一个或几个属性,然后调用表单的 submit() 方法。在 Link 对象的
onclick 事件处理程序中返回 false 值(return false),能阻止浏览
器打开此连接。即 ,如 果有一个这样的连接:< a href="http://www.a.com"
onclick="return false">Go!</a>,那么无论用户怎样点击,都不会去到
www.a.com 网站,除 非用户禁止浏览器运行 JavaScript。应 用于:B utton
对象;Checkbox 对象;Image 对象;Link 对象;Radio 对象;Reset 对
象;Submit 对象
onerror 事件 发生在错误发生的时候。它的事件处理程序通常就叫做
“错误处理程序”(Error Handler),用来处理错误。上边已经介绍过,
要忽略一切错误,就使用:
function ignoreError() {
return true;
}
window.onerror = ignoreError;
应用于:window 对象
onfocus 事件 发生在窗口得到焦点的时候。应用于:window 对象
onload 事件 发生在文档全部下载完毕的时候。全 部下载完毕意味着不但
HTML 文件,而且包含的图片,插件,控件,小程序等全部内容都下载完
毕。本 事件是 window 的事件,但 是在 HTML 中指定事件处理程序的时候,
我们是把它写在<body>标记中的。应用于:window 对象
onmousedown 事件 发生在用户把鼠标放在对象上按下鼠标键的时候。参
考 onmouseup 事件。应用于:Button 对象;Link 对象
onmouseout 事件 发生在鼠标离开对象的时候。参 考 onmouseover 事件。
应用于:Link 对象
onmouseover 事件 发生在鼠标进入对象范围的时候。这个事件和
onmouseout 事件,再加上图片的预读,就可以做到当鼠标移到图像连接
上,图像更改的效果了。有时我们看到,在指向一个连接时,状态栏上不
显示地址,而显示其它的资料,看起来这些资料是可以随时更改的。它们
是这样做出来的:
<a href="..." onmouseover="window.status='Click Me Please!';
return true;" onmouseout="window.status=''; return true;">
应用于:Link 对象
onmouseup 事件 发生在用户把鼠标放在对象上鼠标键被按下的情况下,
放开鼠标键的时候。如果按下鼠标键的时候,鼠标并不在放开鼠标的对象
上,则本事件不会发生。应用于:Button 对象;Link 对象
onreset 事件 发生在表单的“重置”按钮被单击(按下并放开)的时候。
通过在事件处理程序中返回 false 值(return false)可以阻止表单重
置。应用于:Form 对象
onresize 事件 发生在窗口被调整大小的时候。应用于:window 对象
onsubmit 事件 发生在表单的“提交”按钮被单击( 按下并放开)的 时候。
可以使用该事件来验证表单的有效性。通 过在事件处理程序中返回 false
值(return false)可以阻止表单提交。应用于:Form 对象
onunload 事件 发生在用户退出文档(或者关闭窗口,或者到另一个页面
去)的时候。与 onload 一样,要写在 HTML 中就写到<body>标记里。
有的 Web Masters 用这个方法来弹出“调查表单”,以“强迫”来者填
写;有的就弹出广告窗口,唆使来者点击连接。我觉得这种
“onunload="open..."”的方法很不好,有 时甚至会因为弹出太多窗口而
导致资源缺乏。有 什么对来者说就应该在网页上说完,不 对吗? 应用于:
window 对象
Document 文档对象是JavaScript 中window 和frames 对象的一个属性,是显示
于窗口或框架内的一个文档。描述当前窗口或指定窗口对象的文档。它包含了文
档从<head>到</body>的内容。
用法:document (当前窗口) 或 <窗口对象>.document (指定窗口)
属性:
document.title //设置文档标题等价于HTML 的<title>标签
document.bgColor //设置页面背景色
document.fgColor //设置前景色(文本颜色)
document.linkColor //未点击过的链接颜色
document.alinkColor //激活链接(焦点在此链接上)的颜色
document.vlinkColor //已点击过的链接颜色
document.URL //设置URL 属性从而在同一窗口打开另一网页
document.fileCreatedDate //文件建立日期,只读属性
document.fileModifiedDate //文件修改日期,只读属性
document.fileSize //文件大小,只读属性
document.cookie //设置和读出cookie
document.charset //设置字符集 简体中文:gb2312
cookie 关于 cookie 请参看“使用框架和 Cookies”一章。
lastModified 当前文档的最后修改日期,是一个 Date 对象。
referrer 如果当前文档是通过点击连接打开的,则 referrer 返回原来
的 URL。
title 指<head>标记里用<title>...</title>定义的文字。在 Netscape
里本属性不接受赋值。
fgColor 指<body>标记的 text 属性所表示的文本颜色。
bgColor 指<body>标记的 bgcolor 属性所表示的背景颜色。
linkColor 指<body>标记的 link 属性所表示的连接颜色。
alinkColor 指<body>标记的 alink 属性所表示的活动连接颜色。
vlinkColor 指<body>标记的 vlink 属性所表示的已访问连接颜色。
方法:
open() 打开文档以便 JavaScript 能向文档的当前位置(指插入
JavaScript 的位置)写入数据。通常不需要用这个方法,在需要的时候
JavaScript 自动调用。
write(); writeln() 向文档写入数据,所写入的会当成标准文档 HTML
来处理。writeln() 与 write() 的不同点在于,writeln() 在写入数据
以后会加一个换行。这个换行只是在 HTML 中换行,具体情况能不能够是
显示出来的文字换行,要看插入 JavaScript 的位置而定。如在<pre>标
记中插入,这个换行也会体现在文档中。
clear() 清空当前文档。
close() 关闭文档,停止写入数据。如果用了 write[ln]() 或 clear()
方法,就一定要用 close() 方法来保证所做的更改能够显示出来。如果
文档还没有完全读取,也就是说,JavaScript 是插在文档中的,那就不
必使用该方法。
location 地址对象 它描述的是某一个窗口对象所打开的地址。要 表示当前窗口
的地址,只需要使用“location”就行了;若要表示某一个窗口的地址,就使用
“<窗口对象>.location”。先 前写了一片用window.location.href实现刷新另
个框架页面 ,特此我看了一下locaiton 的详细用法,对此有点改进,具体如
下:
注意:属于不同协议或不同主机的两个地址之间不能互相引用对方的 location
对象,这是出于安全性的需要。例如,当前窗口打开的是“www.a.com”下面的
某一页,另外一个窗口(对象名为:bWindow)打开的是“www.b.com”的网页。
如果在当前窗口使用“bWindow.location”,就会出错:“没有权限”。这个错
误是不能用错误处理程序(Event Handler,参阅 onerror 事件)来接收处理的。
第一、简单介绍一下location 属性、用法以及相关示例:
Location
包含了关于当前 URL 的信息。location 对象描述了与一个给定的 Window 对象
关联的完整 URL。location 对象的每个属性都描述了 URL 的不同特性。
通常情况下,一 个 URL 会有下面的格式:协 议//主机:端口/路径名称#哈希标识?
搜索条件
例如:url 这
些部分是满足下列需求的:
“协议”是 URL 的起始部分,直到包含到第一个冒号。
“主机”描述了主机和域名,或者一个网络主机的 IP 地址。
“端口”描述了服务器用于通讯的通讯端口。
路径名称描述了 URL 的路径方面的信息。
“哈希标识”描述了 URL 中的锚名称,包括哈希掩码(#)。此属性只应用
于 HTTP 的 URL。
“搜索条件”描述了该 URL 中的任何查询信息,包括问号。此属性只应
用于 HTTP 的 URL。“搜索条件”字符串包含变量和值的配对;每对之间
由一个“&”连接。
属性概览
protocol 返回地址的协议,取值为 'http:','https:','file:' 等等。
hostname 返回地址的主机名,例如,一个“
http://www.microsoft.com/china/”的地址,location.hostname ==
'www.microsoft.com'。
· port 返回地址的端口号,一般 http 的端口号是 '80'。
· host 返回主机名和端口号,如:'www.a.com:8080'。
· pathname 返回路径名,如“http://www.a.com/b/c.html”,
location.pathname == 'b/c.html'。
· hash 返回“#”以及以后的内容,如“
http://www.a.com/b/c.html#chapter4”,location.hash ==
'#chapter4';如果地址里没有“#”,则返回空字符串。
· search 返回“?”以及以后的内容,如“
http://www.a.com/b/c.asp?selection=3&jumpto=4”,l ocation.search
== '?selection=3&jumpto=4';如果地址里没有“?”,则返回空字符串。
href 返回以上全部内容,也就是说,返回整个地址。在浏览器的地址栏
上怎么显示它就怎么返回。如果想一个窗口对象打开某地址,可以使用
“location.href = '...'”,也可以直接用“location = '...'”来达
到此目的。
方法概览
reload() 相当于按浏览器上的“刷新”(IE)或“Reload”(Netscape)
键。
replace() 打开一个 URL,并取代历史对象中当前位置的地址。用这个方
法打开一个 URL 后,按 下浏览器的“后退”键将不能返回到刚才的页面。
location 之页面跳转js 如下:
//简单跳转
function gotoPage(url) {
// eg. var url =
"newsview.html?catalogid="+catalogID+"&pageid="+pageid;
window.location = url;
}
// 对location 用法的升级,为单个页面传递参数
function goto_catalog(iCat) {
if(iCat<=0) {
top.location = "../index.aspx"; // top 出去
} else {
window.location = "../newsCat.aspx?catid="+iCat;
}
}
对指定框架进行跳转页面,二种方法皆可用
function goto_iframe(url) {
parent.mainFrame.location = "../index.aspx"; //
// parent.document.getElementById("mainFrame").src =
"../index.aspx";// use dom to change page // 同时我增加了dom 的写法
}
// 对指定框架进行跳转页面,因为
parent.iframename.location="../index.aspx"; 方法不能实行,主要是
"parent.iframename" 中的iframename在js 中被默认为节点,而 不能把传递过
来的参数转换过来,所以用dom 实现了该传递二个参数的框架跳转页面,希望那
位仁兄不吝赐教!
function goto_iframe(iframename,url) {
parent.document.getElementById(iframename).src = "../index.aspx";//
use dom to change page by iframeName
//}
// 回到首页
function gohome() {
top.location = "/index.aspx";
}
JavaScript 中的History 历史对象包含了用户已浏览的 URL 的信息,是指历史
对象指浏览器的浏览历史。鉴于安全性的需要,该对象收到很多限制,现在只剩
下下列属性和方法。History 历史对象有length 这个属性,列出历史的项数。
JavaScript 所能管到的历史被限制在用浏览器的“前进”“后退”键可以去到
的范围。本属性返回的是“前进”和“后退”两个按键之下包含的地址数的和。
History 历史对象并有以下方法
back() 后退,跟按下“后退”键是等效的。
forward() 前进,跟按下“前进”键是等效的。
go() 用法:history.go(x);在历史的范围内去到指定的一个地址。如果
x < 0,则后退 x 个地址,如果 x > 0,则前进 x 个地址,如果 x == 0,
则刷新现在打开的网页。history.go(0) 跟 location.reload() 是等效
的。
Window是JavaScript 中最大的对象,它描述的是一个浏览器窗口。一般要引用它的
属性和方法时,不需要用“window.xxx”这种形式,而直接使用“xxx”。一个
框架页面也是一个窗口。
Window 窗口对象有如下属性:
name 窗口的名称,由 打开它的连接( <a target="...">)或 框架页( <frame
name="...">)或某一个窗口调用的 open() 方法(见下)决定。一般我
们不会用这个属性。
status 指窗口下方的“状态栏”所显示的内容。通过对 status 赋值,
可以改变状态栏的显示。
opener 用法:window.opener;返回打开本窗口的窗口对象。注意:返回
的是一个窗口对象。如果窗口不是由其他窗口打开的,在 Netscape 中这
个属性返回 null;在 IE 中返回“未定义”( undefined)。u ndefined 在
一定程度上等于 null。注意:undefined 不是 JavaScript 常数,如果
你企图使用“undefined”,那就真的返回“未定义”了。
self 指窗口本身,它返回的对象跟 window 对象是一模一样的。最常用
的是“self.close()”,放在<a>标记中:“<a
href="javascript:self.close()">关闭窗口</a>”。
parent 返回窗口所属的框架页对象。
top 返回占据整个浏览器窗口的最顶端的框架页对象。
history 历史对象,
location 地址对象,
document 文档对象,
Window 窗口对象有如下方法:
第一个方法是open() 打开一个窗口。
用法:
open(<URL 字符串>, <窗口名称字符串>, <参数字符串>);
说明:
<URL 字符串>:描述所打开的窗口打开哪一个网页。如果留空(''),则
不打开任意网页。
<窗口名称字符串>:描述被打开的窗口的名称(window.name),可以使
用'_top'、'_blank'等内建名称。这里的名称跟“<a href="..."
target="...">”里的“target”属性是一样的。
<参数字符串>:描 述被打开的窗口的样貌。如 果只需要打开一个普通窗口,
该字符串留空(''),如果要指定样貌,就在字符串里写上一到多个参数,
参数之间用逗号隔开。
例:打开一个 400 x 100 的干净的窗口:
open('','_blank','width=400,height=100,menubar=no,toolbar=no,
location=no,directories=no,status=no, scrollbars=yes,resizable=yes')
open()的参数
top=# 窗口顶部离开屏幕顶部的像素数
left=# 窗口左端离开屏幕左端的像素数
width=# 窗口的宽度
height=# 窗口的高度
menubar=... 窗口有没有菜单,取值yes 或no
toolbar=... 窗口有没有工具条,取值yes 或 no
location=... 窗口有没有地址栏,取值yes 或no
directories=... 窗口有没有连接区,取值yes 或no
scrollbars=... 窗口有没有滚动条,取值yes 或no
status=... 窗口有没有状态栏,取值yes 或no
resizable=... 窗口给不给调整大小,取值yes 或no
注意:open() 方法有返回值,返回的就是它打开的窗口对象。比如
var newWindow = open('','_blank');
这样把一个新窗口赋值到“newWindow”变量中,以 后通过“newWindow”变量就
可以控制窗口了。
close() 关闭一个已打开的窗口。
用法:
window.close()
或
self.close()
主要作用是关闭本窗口;
<窗口对象>.close():关闭指定的窗口。注意如果该窗口有状态栏,调用该方法
后浏览器会警告:“网页正在试图关闭窗口,是否关闭?”然后等待用户选择是
否;如果没有状态栏,调用该方法将直接关闭窗口。
另外Window 窗口对象还有如下方法
blur() 使焦点从窗口移走,窗口变为“非活动窗口”。
focus() 是窗口获得焦点,变为“活动窗口”。不过在 Windows 98,该
方法只能使窗口的标题栏和任务栏上的相应按钮闪烁,提 示用户该窗口正
在试图获得焦点。
scrollTo() 用法:&e1;<窗口对象>.&e3;scrollTo(x, y);使窗口滚动,使文档
从左上角数起的(x, y)点滚动到窗口的左上角。
scrollBy() 用法:&e1;<窗口对象>.&e3;scrollBy(deltaX, deltaY);使窗口向
右滚动 deltaX 像素,向下滚动 deltaY 像素。如果取负值,则向相反的
方向滚动。
resizeTo() 用法:&e1;<窗口对象>.&e3;resizeTo(width, height);使窗口调
整大小到宽 width 像素,高 height 像素。
resizeBy() 用法:&e1;<窗口对象>.&e3;resizeBy(deltaWidth, deltaHeight);
使窗口调整大小,宽增大 deltaWidth 像素,高增大 deltaHeight 像素。
如果取负值,则减少。
alert() 用法:alert(<字符串>);弹出一个只包含“确定”按钮的对话
框,显示<字符串>的内容,整个文档的读取、Script 的运行都会暂停,
直到用户按下“确定”。
confirm() 用法:c onfirm(<字符串>);弹 出一个包含“确定”和“取消”
按钮的对话框,显示<字符串>的内容,要求用户做出选择,整个文档的读
取、Script 的运行都会暂停。如果用户按下“确定”,则返回 true 值,
如果按下“取消”,则返回 false 值。
prompt() 用法:prompt(<字符串>[, <初始值>]);弹出一个包含“确
认”“取消”和一个文本框的对话框,显示<字符串>的内容,要求用户在
文本框输入一些数据,整个文档的读取、Script 的运行都会暂停。如果
用户按下“确认”,则 返回文本框里已有的内容,如 果用户按下“取消”,
则返回 null 值。如果指定<初始值>,则文本框里会有默认值。
Window 窗口对象有如下事件:
window.onload;发生在文档全部下载完毕的时候。全部下载完毕意味着不但
HTML 文件,而且包含的图片,插件,控件,小程序等全部内容都下载完毕。本
事件是 window 的事件,但是在 HTML 中指定事件处理程序的时候,我们是把它
写在<body>标记中的。
window.onunload;发生在用户退出文档(或者关闭窗口,或者到另一个页面去)
的时候。与 onload 一样,要写在 HTML 中就写到<body>标记里。
window.onresize;发生在窗口被调整大小的时候。
window.onblur;发生在窗口失去焦点的时候。
window.onfocus;发生在窗口得到焦点的时候。
window.onerror;发生在错误发生的时候。它的事件处理程序通常就叫做
“错误处理程序”(Error Handler),用来处理错误。上边已经介绍过,
要忽略一切错误,就使用:
function ignoreError() {
return true;
}
window.onerror = ignoreError;
navigator 浏览器对象,包含了正在使用的 Navigator 的版本信息。反映了当
前使用的浏览器的资料。JavaScript 客户端运行时刻引擎自动创建 navigator
对象。
包括一下几大属性:
· appCodeName 返回浏览器的“码名”(?),流行的 IE 和 NN 都返回
'Mozilla'。
下面的例子显示了 appCodeName 属性的值:
document.write("navigator.appCodeName 的值是" +
navigator.appCodeName)
· appName 返回浏览器名。I E 返回 'Microsoft Internet Explorer',N N 返
回 'Netscape'。
下面的例子显示了 appName 属性的值:
document.write("navigator.appName 的值是 " + navigator.appName)
· appVersion 返回浏览器版本,包括了大版本号、小版本号、语言、操作
平台等信息。
· language 语言
· mimeType 以数组表示所支持的MIME 类型
· platform 返回浏览器的操作平台,对于 Windows 9x 上的浏览器,返回
'Win32'(大小写可能有差异)。
· userAgent 返回以上全部信息。例如,IE5.01 返回 'Mozilla/4.0
(compatible; MSIE 5.01; Windows 98)'。
· plugins 以数组表示已安装的外挂程序
· javaEnabled() 返回一个布尔值,代表当前浏览器允许不允许 Java。
以下有很多“g/set[UTC]XXX”这样的方法,它表示既有“getXXX”方法,又有
“setXXX”方法。“get”是获得某个数值,而“set”是设定某个数值。如果带
有“UTC”字母,则表示获得/设定的数值是基于 UTC 时间的,没有则表示基于
本地时间或浏览期默认时间的。
如无说明,方法的使用格式为:“<对象>.<方法>”,下同。
g/set[UTC]FullYear() 返回/设置年份,用四位数表示。如果使用
“x.set[UTC]FullYear(99)”,则年份被设定为 0099 年。
g/set[UTC]Year()返回/设置年份,用两位数表示。设定的时候浏览器自动加上
“19”开头,故使用“x.set[UTC]Year(00)”把年份设定为 1900 年。
g/set[UTC]Month()返回/设置月份。
g/set[UTC]Date()返回/设置日期。
g/set[UTC]Day()返回/设置星期,0 表示星期天。
g/set[UTC]Hours()返回/设置小时数,24 小时制。
g/set[UTC]Minutes()返回/设置分钟数。
g/set[UTC]Seconds()返回/设置秒钟数。
g/set[UTC]Milliseconds()返回/设置毫秒数。
g/setTime() 返回/设置时间,该 时间就是日期对象的内部处理方法:从 1970 年
1 月 1 日零时正开始计算到日期对象所指的日期的毫秒数。如果要使某日期对
象所指的时间推迟 1 小时,就用:“x.setTime(x.getTime() + 60 * 60 *
1000);”(一小时 60 分,一分 60 秒,一秒 1000 毫秒)。
getTimezoneOffset() 返回日期对象采用的时区与格林威治时间所差的分钟数。
在格林威治东方的市区,该值为负,例如:中国时区(GMT+0800)返回“-480”。
toString() 返回一个字符串,描述日期对象所指的日期。这个字符串的格式类
似于:“Fri Jul 21 15:43:46 UTC+0800 2000”。
toLocaleString() 返回一个字符串,描述日期对象所指的日期,用本地时间表
示格式。如:“2000-07-21 15:43:46”。
toGMTString() 返回一个字符串,描述日期对象所指的日期,用 GMT 格式。
toUTCString() 返回一个字符串,描述日期对象所指的日期,用 UTC 格式。
parse() 用法:Date.parse(<日期对象>);返回该日期对象的内部表达方式。
Math “数学”对象,提供对数据的数学计算。下面所提到的属性和方法,大家在使用的时候记住用“Math.<名>”这种格式。
属性
E 返回常数 e (2.718281828...)。
LN2 返回 2 的自然对数 (ln 2)。
LN10 返回 10 的自然对数 (ln 10)。
LOG2E 返回以 2 为低的 e 的对数 (log2e)。
LOG10E 返回以 10 为低的 e 的对数 (log10e)。
PI 返回π(3.1415926535...)。
SQRT1_2 返回 1/2 的平方根。
SQRT2 返回 2 的平方根。
方法
abs(x) 返回 x 的绝对值。
acos(x) 返回 x 的反余弦值(余弦值等于 x 的角度),用弧度表示。
asin(x) 返回 x 的反正弦值。
atan(x) 返回 x 的反正切值。
atan2(x, y) 返回复平面内点(x, y)对应的复数的幅角,用 弧度表示,其 值在 -π
到 π 之间。
ceil(x) 返回大于等于 x 的最小整数。
cos(x) 返回 x 的余弦。
exp(x) 返回 e 的 x 次幂 (ex)。
floor(x) 返回小于等于 x 的最大整数。
log(x) 返回 x 的自然对数 (ln x)。
max(a, b) 返回 a, b 中较大的数。
min(a, b) 返回 a, b 中较小的数。
pow(n, m) 返回 n 的 m 次幂 (nm)。
random() 返回大于 0 小于 1 的一个随机数。
round(x) 返回 x 四舍五入后的值。
sin(x) 返回 x 的正弦。
sqrt(x) 返回 x 的平方根。
tan(x) 返回 x 的正切。
Date 日期对象。这个对象可以储存任意一个日期,从 0001 年到 9999 年,并
且可以精确到毫秒数( 1/1000 秒)。在 内部,日 期对象是一个整数,它 是从 1970
年 1 月 1 日零时正开始计算到日期对象所指的日期的毫秒数。如 果所指日期比
1970 年早,则它是一个负数。所有日期时间,如果不指定时区,都采用“UTC”
(世界时)时区,它与“GMT”(格林威治时间)在数值上是一样的。
定义一个日期对象:
var d = new Date;
这个方法使 d 成为日期对象,并且已有初始值:当前时间。如果要自定初始值,
可以用:
var d = new Date(99, 10, 1); //99 年 10 月 1 日
var d = new Date('Oct 1, 1999'); //99 年 10 月 1 日
toString() 用法:<数值变量>.toString();返回:字符串形式的数值。如:若
a == 123;则 a.toString() == '123'。
String 字符串对象。声明一个字符串对象最简单、快捷、有效、常用的方法就
是直接赋值。
length 用法:<字符串对象>.length;返回该字符串的长度。
charAt() 用法:<字符串对象>.charAt(<位置>);返回该字符串位于第<位置>
位的单个字符。注 意:字 符串中的一个字符是第 0 位的,第 二个才是第 1 位的,
最后一个字符是第 length - 1 位的。
charCodeAt() 用法:<字符串对象>.charCodeAt(<位置>);返回该字符串位于第
<位置>位的单个字符的 ASCII 码。
fromCharCode() 用法:String.fromCharCode(a, b, c...);返回一个字符串,
该字符串每个字符的 ASCII 码由 a, b, c... 等来确定。
indexOf() 用法:<字符串对象>.indexOf(<另一个字符串对象>[, <起始位置
>]);该方法从<字符串对象>中查找<另一个字符串对象>(如果给出<起始位置>
就忽略之前的位置),如果找到了,就返回它的位置,没有找到就返回“-1”。
所有的“位置”都是从零开始的。
lastIndexOf() 用法:<字符串对象>.lastIndexOf(<另一个字符串对象>[, <起
始位置>]);跟 indexOf() 相似,不过是从后边开始找。
split() 用法:<字符串对象>.split(<分隔符字符>);返回一个数组,该数组是
从<字符串对象>中分离开来的,<分隔符字符>决定了分离的地方,它本身不会包
含在所返回的数组中。例 如:' 1&2&345&678'.split('&')返回数组:1 ,2,345,678。
关于数组,我们等一下就讨论。
substring() 用法:<字符串对象>.substring(<始>[, <终>]);返回原字符串的
子字符串,该字符串是原字符串从<始>位置到<终>位置的前一位置的一段。<终>
- <始> = 返回字符串的长度(length)。如果没有指定<终>或指定得超过字符
串长度,则子字符串从<始>位置一直取到原字符串尾。如果所指定的位置不能返
回字符串,则返回空字符串。
substr() 用法:<字符串对象>.substr(<始>[, <长>]);返回原字符串的子字符
串,该字符串是原字符串从<始>位置开始,长度为<长>的一段。如果没有指定<
长>或指定得超过字符串长度,则子字符串从<始>位置一直取到原字符串尾。如
果所指定的位置不能返回字符串,则返回空字符串。
toLowerCase() 用法:<字符串对象>.toLowerCase();返回把原字符串所有大写
字母都变成小写的字符串。
toUpperCase() 用法:<字符串对象>.toUpperCase();返回把原字符串所有小写
字母都变成大写的字符串。
Array 数组对象。数组对象是一个对象的集合,里边的对象可以是不同类型的。
数组的每一个成员对象都有一个“下标”,用来表示它在数组中的位置(既然是
“位置”,就也是从零开始的啦)。
数组的定义方法:
var <数组名> = new Array();
这样就定义了一个空数组。以后要添加数组元素,就用:
<数组名>[<下标>] = ...;
注意这里的方括号不是“可以省略”的意思,数 组的下标表示方法就是用方括号
括起来。
如果想在定义数组的时候直接初始化数据,请用:
var <数组名> = new Array(<元素1>, <元素 2>, <元素3>...);
例如,var myArray = new Array(1, 4.5, 'Hi'); 定义了一个数组 myArray,
里边的元素是:myArray[0] == 1; myArray[1] == 4.5; myArray[2] == 'Hi'。
但是,如果元素列表中只有一个元素,而这个元素又是一个正整数的话,这将定
义一个包含<正整数>个空元素的数组。
注意:JavaScript 只有一维数组!千万不要用“Array(3,4)”这种愚蠢的方法
来定义 4 x 5 的二维数组,或者用“myArray[2,3]”这种方法来返回“二维数
组”中的元素。任意“myArray[...,3]”这种形式的调用其实只返回了
“myArray[3]”。要使用多维数组,请用这种虚拟法:
var myArray = new Array(new Array(), new Array(), new Array(), ...);
其实这是一个一维数组,里边的每一个元素又是一个数组。调用这个“二维数
组”的元素时:myArray[2][3] = ...;
属性
length 用法:<数组对象>.length;返回:数组的长度,即数组里有多少个元素。
它等于数组里最后一个元素的下标加一。所以,想添加一个元素,只需要:
myArray[myArray.length] = ...。
方法
join() 用法:<数组对象>.join(<分隔符>);返回一个字符串,该字符串把数组
中的各个元素串起来,用<分隔符>置于元素与元素之间。这个方法不影响数组原
本的内容。
reverse() 用法:<数组对象>.reverse();使数组中的元素顺序反过来。如果对
数组[1, 2, 3]使用这个方法,它将使数组变成:[3, 2, 1]。
slice() 用法:<数组对象>.slice(<始>[, <终>]);返回一个数组,该数组是原
数组的子集,始于<始>,终于<终>。如果不给出<终>,则子集一直取到原数组的
结尾。
sort() 用法:<数组对象>.sort([<方法函数>]);使数组中的元素按照一定的顺
序排列。如果不指定<方法函数>,则按字母顺序排列。在这种情况下,80 是比 9
排得前的。如果指定<方法函数>,则按<方法函数>所指定的排序方法排序。<方
法函数>比较难讲述,这里只将一些有用的<方法函数>介绍给大家。
按升序排列数字:
function sortMethod(a, b) {
return a - b;
}
myArray.sort(sortMethod);
按降序排列数字:把上面的“a - b”该成“b - a”。
添加css样式
<html>
<head>
<style>
.over{
color:red;
background:#888;
}
</style>
<script src="../../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){
$("div").bind("mouseover mouseout", function(){
$(this).toggleClass("over");
});
})
</script>
</head>
<body>
<div style="width:100px;height:50px;">滑入.</div>
</body>
</html>
根据事件类型
<html>
<head>
<script src="../../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){
$("div").bind("click.plugin",function(){
$("body").append("<p>click事件</p>");
});
$("div").bind("mouseover.plugin", function(){
$("body").append("<p>mouseover事件</p>");
});
$("div").bind("dblclick", function(){
$("body").append("<p>dblclick事件</p>");
});
$("button").click(function() {
$("div").unbind(".plugin");
})
})
</script>
</head>
<body>
<div style="width:100px;height:50px;background:#888;color:white;">test.</div>
<button >根据命名空间,删除事件</button>
</body>
</html>
相同事件名称,不同命名空间执行方法
<html>
<head>
<script src="../../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){
$("div").bind("click",function(){
$("body").append("<p>click事件</p>");
});
$("div").bind("click.plugin", function(){
$("body").append("<p>click.plugin事件</p>");
});
$("button").click(function() {
$("div").trigger("click!"); // 注意click后面的感叹号
});
})
</script>
</head>
<body>
<div style="width:100px;height:50px;background:#888;color:white;">test.</div>
<button >根据命名空间,触发事件</button>
</body>
</html>
<html>
<head>
<style type="text/css">
*{margin:0;padding:0;}
body { font-size: 13px; line-height: 130%; padding: 60px; }
p {width:200px;background:#888;color:white;height:16px;}
</style>
<script src="../../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){
$('#btn').bind("myClick", function(){
$('#test').append("<p>我的自定义事件.</p>");
});
$('#btn').click(function(){
$(this).trigger("myClick");
}).trigger("myClick");
})
</script>
</head>
<body>
<button id="btn">点击我</button>
<div id="test"></div>
</body>
</html>
<html>
<title></title>
<style type="text/css">
*{margin:0;padding:0;}
body { font-size: 13px; line-height: 130%; padding: 60px; }
p {width:200px;background:#888;color:white;height:16px;}
</style>
<script src="../../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){
$('#old').bind("click", function(){
$("input").trigger("focus");
});
$('#new').bind("click", function(){
$("input").triggerHandler("focus");
});
$("input").focus(function(){
$("body").append("<p>focus.</p>");
})
})
</script>
</head>
<body>
<button id="old">trigger</button>
<button id="new">triggerHandler</button>
<input />
</body>
</html>
<html>
<head>
<style type="text/css">
*{margin:0;padding:0;}
body { font-size: 13px; line-height: 130%; padding: 60px; }
p {width:200px;background:#888;color:white;height:16px;}
</style>
<script src="../../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){
$('#btn').bind("click", function(){
$('#test').append("<p>我的绑定函数1</p>");
}).bind("click", function(){
$('#test').append("<p>我的绑定函数2</p>");
}).bind("click", function(){
$('#test').append("<p>我的绑定函数3</p>");
});
$('#delAll').click(function(){
$('#btn').unbind("click");
});
$('#delTwo').click(function(){
$('#btn').unbind("click",myFun2);
});
})
</script>
</head>
<body>
<button id="btn">点击我</button>
<div id="test"></div>
<button id="delAll">删除所有事件</button>
<button id="delTwo">删除第二个事件</button>
</body>
</html>
<html>
<head>
<style type="text/css">
*{margin:0;padding:0;}
body { font-size: 13px; line-height: 130%; padding: 60px; }
p {width:200px;background:#888;color:white;height:16px;}
</style>
<script src="../../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){
$('#btn').one("click", function(){
$('#test').append("<p>我的绑定函数1</p>");
}).one("click", function(){
$('#test').append("<p>我的绑定函数2</p>");
}).one("click", function(){
$('#test').append("<p>我的绑定函数3</p>");
});
})
</script>
</head>
<body>
<button id="btn">点击我</button>
<div id="test"></div>
</body>
</html>
<html>
<head>
<script src="../../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script>
$(function(){
$("a").click(function(event) {
alert(event.type);//获取事件类型
alert(event.target.href);//获取触发事件的<a>元素的href属性值
alert("Current mouse position: " + event.pageX + ", " + event.pageY );//获取鼠标当前相对于页面的坐标
alert(e.which) // 1 = 鼠标左键 left; 2 = 鼠标中键; 3 = 鼠标右键
return false;//阻止链接跳转
});
})
</script>
</head>
<body>
<a href='http://google.com'>click me .</a>
</body>
</html>
<html>
<head>
<script src="../../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){
$("#sub").bind("click",function(event){
var username = $("#username").val(); //获取元素的值
if(username==""){ //判断值是否为空
$("#msg").html("<p>文本框的值不能为空.</p>"); //提示信息
event.preventDefault(); //阻止默认行为 ( 表单提交 )或者return false;
}
})
})
</script>
</head>
<body>
<form action="test.html">
用户名:<input type="text" id="username" />
<br/>
<input type="submit" value="提交" id="sub"/>
</form>
<div id="msg"></div>
</body>
</html>
<html>
<head>
<style type="text/css">
*{margin:0;padding:0;}
body { font-size: 13px; line-height: 130%; padding: 60px; }
#content { width: 220px; border: 1px solid #0050D0;background: #96E555 }
span { width: 200px; margin: 10px; background: #666666; cursor: pointer;color:white;display:block;}
p {width:200px;background:#888;color:white;height:16px;}
</style>
<script src="../../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){
// 为span元素绑定click事件
$('span').bind("click",function(event){
var txt = $('#msg').html() + "<p>内层span元素被点击.<p/>";
$('#msg').html(txt);
event.stopPropagation(); // 阻止事件冒泡或者return false;
});
// 为div元素绑定click事件
$('#content').bind("click",function(event){
var txt = $('#msg').html() + "<p>外层div元素被点击.<p/>";
$('#msg').html(txt);
event.stopPropagation(); // 阻止事件冒泡或者return false;
});
// 为body元素绑定click事件
$("body").bind("click",function(){
var txt = $('#msg').html() + "<p>body元素被点击.<p/>";
$('#msg').html(txt);
});
})
</script>
</head>
<body>
<div id="content">
外层div元素
<span>内层span元素</span>
外层div元素
</div>
<div id="msg"></div>
</body>
</html>
<html>
<head>
<script src="../../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){
$("#panel h5.head").hover(function(){//鼠标移动事件
$(this).next().show();
},function(){
$(this).next().hide();
})
})
</script>
</head>
<body>
<div id="panel">
<h5 class="head">什么是jQuery?</h5>
<div class="content">
jQuery是继Prototype之后又一个优秀的JavaScript库,它是一个由 John Resig 创建于2006年1月的开源项目。jQuery凭借简洁的语法和
跨平台的兼容性,极大地简化了JavaScript开发人员遍历HTML文档、操作DOM、处理事件、执行动画和开发Ajax。它独特而又优雅的代码风格改变了
JavaScript程序员的设计思路和编写程序的方式。
</div>
</div>
</body>
</html>
<html>
<head>
<script src="../../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<style type="text/css">
.highlight{ background:#FF3300; }
</style>
<script type="text/javascript">
$(function(){
$("#panel h5.head").toggle(function(){//鼠标点击事件
$(this).addClass("highlight");
$(this).next().show();
},function(){
$(this).removeClass("highlight");
$(this).next().hide();
});
})
</script>
</head>
<body>
<div id="panel">
<h5 class="head">什么是jQuery?</h5>
<div class="content">
jQuery是继Prototype之后又一个优秀的JavaScript库,它是一个由 John Resig 创建于2006年1月的开源项目。jQuery凭借简洁的语法和
跨平台的兼容性,极大地简化了JavaScript开发人员遍历HTML文档、操作DOM、处理事件、执行动画和开发Ajax。它独特而又优雅的代码风格改变了
JavaScript程序员的设计思路和编写程序的方式。
</div>
</div>
</body>
</html>
<head>
<script src="../../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){
$("#panel h5.head").bind("click",function(){
var $content = $(this).next();
if($content.is(":visible")){
$content.hide();
}else{
$content.show();
}
})
})
</script>
</head>
<body>
<div id="panel">
<h5 class="head">什么是jQuery?</h5>
<div class="content">
jQuery是继Prototype之后又一个优秀的JavaScript库,它是一个由 John Resig 创建于2006年1月的开源项目。jQuery凭借简洁的语法和
跨平台的兼容性,极大地简化了JavaScript开发人员遍历HTML文档、操作DOM、处理事件、执行动画和开发Ajax。它独特而又优雅的代码风格改变了
JavaScript程序员的设计思路和编写程序的方式。
</div>
</div>
</body>
</html>
<html >
<head>
<script src="../../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){
$("#panel h5.head").bind("mouseover",function(){
$(this).next().show();
});
$("#panel h5.head").bind("mouseout",function(){
$(this).next().hide();
})
})
</script>
</head>
<body>
<div id="panel">
<h5 class="head">什么是jQuery?</h5>
<div class="content">
jQuery是继Prototype之后又一个优秀的JavaScript库,它是一个由 John Resig 创建于2006年1月的开源项目。jQuery凭借简洁的语法和
跨平台的兼容性,极大地简化了JavaScript开发人员遍历HTML文档、操作DOM、处理事件、执行动画和开发Ajax。它独特而又优雅的代码风格改变了
JavaScript程序员的设计思路和编写程序的方式。
</div>
</div>
</body>
</html>
<html>
<head>
<script src="../../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){
$("#panel h5.head").mouseover(function(){
$(this).next().show();
});
$("#panel h5.head").mouseout(function(){
$(this).next().hide();
})
})
</script>
</head>
<body>
<div id="panel">
<h5 class="head">什么是jQuery?</h5>
<div class="content">
jQuery是继Prototype之后又一个优秀的JavaScript库,它是一个由 John Resig 创建于2006年1月的开源项目。jQuery凭借简洁的语法和
跨平台的兼容性,极大地简化了JavaScript开发人员遍历HTML文档、操作DOM、处理事件、执行动画和开发Ajax。它独特而又优雅的代码风格改变了
JavaScript程序员的设计思路和编写程序的方式。
</div>
</div>
</body>
</html>
<head>
<script src="../../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script type="text/javascript">
var startTime = new Date().getTime();
$(document).ready(function(){
test1();
})
function test1(){
var endTime2 = new Date().getTime();
var a = endTime2 - startTime;
$("<div>jQuery的ready() : "+a+" ms</div>").appendTo("body");
}
function test2(){
var endTime1 = new Date().getTime();
var b = endTime1 - startTime;
$("<p>JavaScript的window.onload : "+b+" ms</p>").appendTo("body");
}
</script>
</head>
<body onload="test2();">
<img src="demo.jpg" style="width:200px;height:200px;"/>
</body>
</html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function(){
//重置表单元素
$(":reset").click(function(){
setTimeout(function() {
countChecked();
$("select").change();
},0);
});
//对表单内 可用input 赋值操作.
$('#btn1').click(function(){
$("#form1 input:enabled").val("这里变化了!");
return false;
})
//对表单内 不可用input 赋值操作.
$('#btn2').click(function(){
$("#form1 input:disabled").val("这里变化了!");
return false;
})
//使用:checked选择器,来操作多选框.
$(":checkbox").click(countChecked);
function countChecked() {
var n = $("input:checked").length;
$("div").eq(0).html("<strong>有"+n+" 个被选中!</strong>");
}
countChecked();//进入页面就调用.
//使用:selected选择器,来操作下拉列表.
$("select").change(function () {
var str = "";
$("select :selected").each(function () {
str += $(this).text() + ",";
});
$("div").eq(1).html("<strong>你选中的是:"+str+"</strong>");
}).trigger('change');
// trigger('change') 在这里的意思是:
// select加载后,马上执行onchange.
// 也可以用.change()代替.
});
</script>
</head>
<body>
<h3> 表单对象属性过滤选择器.</h3>
<form id="form1" action="#">
<button type="reset">重置所有表单元素</button>
<br /><br />
<button id="btn1">对表单内 可用input 赋值操作.</button>
<button id="btn2">对表单内 不可用input 赋值操作.</button><br /><br />
可用元素:<input name="add" value="可用文本框"/> <br/>
不可用元素:<input name="email" disabled="disabled" value="不可用文本框"/><br/>
可用元素: <input name="che" value="可用文本框" /><br/>
不可用元素:<input name="name" disabled="disabled" value="不可用文本框"/><br/>
<br/>
多选框:<br/>
<input type="checkbox" name="newsletter" checked="checked" value="test1" />test1
<input type="checkbox" name="newsletter" value="test2" />test2
<input type="checkbox" name="newsletter" value="test3" />test3
<input type="checkbox" name="newsletter" checked="checked" value="test4" />test4
<input type="checkbox" name="newsletter" value="test5" />test5
<div></div>
<br/><br/>
下拉列表1:<br/>
<select name="test" multiple="multiple" style="height:100px">
<option>浙江</option>
<option selected="selected">湖南</option>
<option>北京</option>
<option selected="selected">天津</option>
<option>广州</option>
<option>湖北</option>
</select>
<br/><br/>
下拉列表2:<br/>
<select name="test2" >
<option>浙江</option>
<option>湖南</option>
<option selected="selected">北京</option>
<option>天津</option>
<option>广州</option>
<option>湖北</option>
</select>
<br/><br/>
<div></div>
</form>
</body>
</html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function(){
var $alltext = $("#form1 :text");
var $allpassword= $("#form1 :password");
var $allradio= $("#form1 :radio");
var $allcheckbox= $("#form1 :checkbox");
var $allsubmit= $("#form1 :submit");
var $allimage= $("#form1 :image");
var $allreset= $("#form1 :reset");
var $allbutton= $("#form1 :button"); // <input type=button /> 和 <button ></button>都可以匹配
var $allfile= $("#form1 :file");
var $allhidden= $("#form1 :hidden"); // <input type="hidden" />和<div style="display:none">test</div>都可以匹配.
var $allselect = $("#form1 select");
var $alltextarea = $("#form1 textarea");
var $AllInputs = $("#form1 :input");
var $inputs = $("#form1 input");
$("div").append(" 有" + $alltext.length + " 个( :text 元素)<br/>")
.append(" 有" + $allpassword.length + " 个( :password 元素)<br/>")
.append(" 有" + $allradio.length + " 个( :radio 元素)<br/>")
.append(" 有" + $allcheckbox.length + " 个( :checkbox 元素)<br/>")
.append(" 有" + $allsubmit.length + " 个( :submit 元素)<br/>")
.append(" 有" + $allimage.length + " 个( :image 元素)<br/>")
.append(" 有" + $allreset.length + " 个( :reset 元素)<br/>")
.append(" 有" + $allbutton.length + " 个( :button 元素)<br/>")
.append(" 有" + $allfile.length + " 个( :file 元素)<br/>")
.append(" 有" + $allhidden.length + " 个( :hidden 元素)<br/>")
.append(" 有" + $allselect.length + " 个( select 元素)<br/>")
.append(" 有" + $alltextarea.length + " 个( textarea 元素)<br/>")
.append(" 表单有 " + $inputs.length + " 个(input)元素。<br/>")
.append(" 总共有 " + $AllInputs.length + " 个(:input)元素。<br/>")
.css("color", "red")
$("form").submit(function () { return false; }); // return false;不能提交.
});
</script>
</head>
<body>
<form id="form1" action="#">
<input type="button" value="Button"/><br/>
<input type="checkbox" name="c"/>1<input type="checkbox" name="c"/>2<input type="checkbox" name="c"/>3<br/>
<input type="file" /><br/>
<input type="hidden" /><div style="display:none">test</div><br/>
<input type="image" /><br/>
<input type="password" /><br/>
<input type="radio" name="a"/>1<input type="radio" name="a"/>2<br/>
<input type="reset" /><br/>
<input type="submit" value="提交"/><br/>
<input type="text" /><br/>
<select><option>Option</option></select><br/>
<textarea rows="5" cols="20"></textarea><br/>
<button>Button</button><br/>
</form>
<div></div>
</body>
</html>
//选取每个父元素下的第2个子元素
$('#btn1').click(function(){
$('div.one :nth-child(2)').css("background","#bbffaa");
})
//选取每个父元素下的第一个子元素
$('#btn2').click(function(){
$('div.one :first-child').css("background","#bbffaa");
})
//选取每个父元素下的最后一个子元素
$('#btn3').click(function(){
$('div.one :last-child').css("background","#bbffaa");
})
//如果父元素下的仅仅只有一个子元素,那么选中这个子元素
$('#btn4').click(function(){
$('div.one :only-child').css("background","#bbffaa");
})
//选取含有 属性title 的div元素.
$('#btn1').click(function(){
$('div[title]').css("background","#bbffaa");
})
//选取 属性title值等于 test 的div元素.
$('#btn2').click(function(){
$('div[title=test]').css("background","#bbffaa");
})
//选取 属性title值不等于 test 的div元素.
$('#btn3').click(function(){
$('div[title!=test]').css("background","#bbffaa");
})
//选取 属性title值 以 te 开始 的div元素.
$('#btn4').click(function(){
$('div[title^=te]').css("background","#bbffaa");
})
//选取 属性title值 以 est 结束 的div元素.
$('#btn5').click(function(){
$("div[title$=est]").css("background","#bbffaa");
})
//选取 属性title值 含有 es 的div元素.
$('#btn6').click(function(){
$("div[title*=es]").css("background","#bbffaa");
})
//组合属性选择器,首先选取有属性id的div元素,然后在结果中 选取属性title值 含有 es 的元素.
$('#btn7').click(function(){
$("div[id][title*=es]").css("background","#bbffaa");
})
$('#reset').click(function(){
window.location.reload();
})
//给id为mover的元素添加动画.
function animateIt() {
$("#mover").slideToggle("slow", animateIt);
}
animateIt();
//选取所有不可见的元素.包括<input type="hidden"/>.
$('#btn_hidden').click(function(){
alert( "不可见的元素有:"+$('body :hidden').length +"个!\n"+
"其中不可见的div元素有:"+$('div:hidden').length+"个!\n"+
"其中文本隐藏域有:"+$('input:hidden').length+"个!");
$('div:hidden').show(3000).css("background","#bbffaa");
})
//选取所有可见的元素.
$('#btn_visible').click(function(){
$('div:visible').css("background","#FF6500");
})
//选取含有文本"di"的div元素.
$('#btn1').click(function(){
$('div:contains(di)').css("background","#bbffaa");
})
//选取不包含子元素(或者文本元素)的div空元素.
$('#btn2').click(function(){
$('div:empty').css("background","#bbffaa");
})
//选取含有class为mini元素 的div元素.
$('#btn3').click(function(){
$('div:has(.mini)').css("background","#bbffaa");
})
//选取含有子元素(或者文本元素)的div元素.
$('#btn4').click(function(){
$('div:parent').css("background","#bbffaa");
})
//选择第一个div元素.
$('#btn1').click(function(){
$('div:first').css("background","#bfa");
})
//选择最后一个div元素.
$('#btn2').click(function(){
$('div:last').css("background","#bfa");
})
//选择class不为one的 所有div元素.
$('#btn3').click(function(){
$('div:not(.one)').css("background","#bfa");
})
//选择 索引值为偶数 的div元素。
$('#btn4').click(function(){
$('div:even').css("background","#bfa");
})
//选择 索引值为奇数 的div元素。
$('#btn5').click(function(){
$('div:odd').css("background","#bfa");
})
//选择 索引等于 3 的元素
$('#btn6').click(function(){
$('div:eq(3)').css("background","#bfa");
})
//选择 索引大于 3 的元素
$('#btn7').click(function(){
$('div:gt(3)').css("background","#bfa");
})
//选择 索引小于 3 的元素
$('#btn8').click(function(){
$('div:lt(3)').css("background","#bfa");
})
//选择 所有的标题元素.比如h1, h2, h3等等...
$('#btn9').click(function(){
$(':header').css("background","#bfa");
})
//选择 当前正在执行动画的所有元素.
$('#btn10').click(function(){
$(':animated').css("background","#bfa");
});
//选择 body内的所有div元素.
$('#btn1').click(function(){
$('body div').css("background","#bbffaa");
})
//在body内的选择 元素名是div 的子元素.
$('#btn2').click(function(){
$('body > div').css("background","#bbffaa");
})
//选择 所有class为one 的下一个div元素.
$('#btn3').click(function(){
$('.one + div').css("background","#bbffaa");
})
//选择 id为two的元素后面的所有div兄弟元素.
$('#btn4').click(function(){
$('#two ~ div').css("background","#bbffaa");
})
//选择 id为 one 的元素
$('#btn1').click(function(){
$('#one').css("background","#bfa");
});
//选择 class 为 mini 的所有元素
$('#btn2').click(function(){
$('.mini').css("background","#bfa");
});
//选择 元素名是 div 的所有元素
$('#btn3').click(function(){
$('div').css("background","#bfa");
});
//选择 所有的元素
$('#btn4').click(function(){
$('*').css("background","#bfa");
});
//选择 所有的span元素和id为two的div元素
$('#btn5').click(function(){
$('span,#two').css("background","#bfa");
});
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="../../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){
var x = 10;
var y = 20;
$("a.tooltip").mouseover(function(e){
this.myTitle = this.title;
this.title = "";
var tooltip = "<div id='tooltip'>"+ this.myTitle +"<\/div>"; //创建 div 元素
$("body").append(tooltip); //把它追加到文档中
$("#tooltip")
.css({
"top": (e.pageY+y) + "px",
"left": (e.pageX+x) + "px"
}).show("fast"); //设置x坐标和y坐标,并且显示
}).mouseout(function(){
this.title = this.myTitle;
$("#tooltip").remove(); //移除
}).mousemove(function(e){
$("#tooltip")
.css({
"top": (e.pageY+y) + "px",
"left": (e.pageX+x) + "px"
});
});
})
</script>
<style type="text/css">
body{
margin:0;
padding:40px;
background:#fff;
font:80% Arial, Helvetica, sans-serif;
color:#555;
line-height:180%;
}
p{
clear:both;
margin:0;
padding:.5em 0;
}
/* tooltip */
#tooltip{
position:absolute;
border:1px solid #333;
background:#f7f5d1;
padding:1px;
color:#333;
display:none;
}
</style>
</head>
<body>
<p><a href="#" class="tooltip" title="这是我的超链接提示1.">提示1.</a></p>
<p><a href="#" class="tooltip" title="这是我的超链接提示2.">提示2.</a></p>
<p><a href="#" title="这是自带提示1.">自带提示1.</a></p>
<p><a href="#" title="这是自带提示2.">自带提示2.</a> </p>
</body>
</html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="../../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){
var $body = $("body").children();
var $p = $("p").children();
var $ul = $("ul").children();
alert( $body.length ); // <body>元素下有2个子元素
alert( $p.length ); // <p>元素下有0个子元素
alert( $ul.length ); // <p>元素下有3个子元素
for(var i=0;i< $ul.length;i++){
alert( $ul[i].innerHTML );
}
});
</script>
</head>
<body>
<p title="选择你最喜欢的水果." >你最喜欢的水果是?</p>
<ul>
<li title='苹果'>苹果</li>
<li title='橘子'>橘子</li>
<li title='菠萝'>菠萝</li>
</ul>
</body>
</html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="../../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){
var $p1 = $("p").next();
alert( $p1.html() ); // 紧邻<p>元素后的同辈元素
var $ul = $("ul").prev();
alert( $ul.html() ); // 紧邻<ul>元素前的同辈元素
var $p2 = $("p").siblings();
alert( $p2.html() ); // 紧邻<p>元素的唯一同辈元素
});
</script>
</head>
<body>
<p title="选择你最喜欢的水果." >你最喜欢的水果是?</p>
<ul>
<li title='苹果'>苹果</li>
<li title='橘子'>橘子</li>
<li title='菠萝'>菠萝</li>
</ul>
</body>
</html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="../../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){
$(document).bind("click", function (e) {
$(e.target).closest("li").css("color","red");
})
});
</script>
</head>
<body>
<p title="选择你最喜欢的水果." >你最喜欢的水果是?</p>
<ul>
<li title='苹果'>苹果</li>
<li title='橘子'>橘子</li>
<li title='菠萝'>菠萝</li>
</ul>
</body>
</html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css">
.test{
font-weight:bold;
color : red;
}
.add{
font-style:italic;
}
</style>
<!-- 引入jQuery -->
<script src="../../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){
//获取<p>元素的HTML代码
$("input:eq(0)").click(function(){
alert( $("p").html() );
});
//获取<p>元素的文本
$("input:eq(1)").click(function(){
alert( $("p").text() );
});
//设置<p>元素的HTML代码
$("input:eq(2)").click(function(){
$("p").html("<strong>你最喜欢的水果是?</strong>");
});
//设置<p>元素的文本
$("input:eq(3)").click(function(){
$("p").text("你最喜欢的水果是?");
});
//设置<p>元素的文本
$("input:eq(4)").click(function(){
$("p").text("<strong>你最喜欢的水果是?</strong>");
});
//获取按钮的value值
$("input:eq(5)").click(function(){
alert( $(this).val() );
});
//设置按钮的value值
$("input:eq(6)").click(function(){
$(this).val("我被点击了!");
});
});
</script>
</head>
<body>
<input type="button" value="获取<p>元素的HTML代码"/>
<input type="button" value="获取<p>元素的文本"/>
<input type="button" value="设置<p>元素的HTML代码"/>
<input type="button" value="设置<p>元素的文本"/>
<input type="button" value="设置<p>元素的文本(带HTML)"/>
<input type="button" value="获取按钮的value值"/>
<input type="button" value="设置按钮的value值"/>
<p title="选择你最喜欢的水果." ><strong>你最喜欢的水果是?</strong></p>
<ul>
<li title='苹果'>苹果</li>
<li title='橘子'>橘子</li>
<li title='菠萝'>菠萝</li>
</ul>
</body>
</html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="../../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){
$("#address").focus(function(){ // 地址框获得鼠标焦点
var txt_value = $(this).val(); // 得到当前文本框的值
if(txt_value==this.defaultValue){
$(this).val(""); // 如果符合条件,则清空文本框内容
}
});
$("#address").blur(function(){ // 地址框失去鼠标焦点
var txt_value = $(this).val(); // 得到当前文本框的值
if(txt_value==""){
$(this).val(this.defaultValue);// 如果符合条件,则设置内容
}
})
$("#password").focus(function(){
var txt_value = $(this).val();
if(txt_value==this.defaultValue){
$(this).val("");
}
});
$("#password").blur(function(){
var txt_value = $(this).val();
if(txt_value==""){
$(this).val(this.defaultValue);
}
})
});
</script>
</head>
<body>
<input type="text" id="address" value="请输入邮箱地址"/> <br/><br/>
<input type="text" id="password" value="请输入邮箱密码"/> <br/><br/>
<input type="button" value="登陆"/>
</body>
</html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css">
.test{
font-weight:bold;
color : red;
}
.add{
font-style:italic;
}
</style>
<script src="../../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){
//设置单选下拉框选中
$("input:eq(0)").click(function(){
$("#single option").removeAttr("selected"); //移除属性selected
$("#single option:eq(1)").attr("selected",true); //设置属性selected
});
//设置多选下拉框选中
$("input:eq(1)").click(function(){
$("#multiple option").removeAttr("selected"); //移除属性selected
$("#multiple option:eq(2)").attr("selected",true);//设置属性selected
$("#multiple option:eq(3)").attr("selected",true);//设置属性selected
});
//设置单选框和多选框选中
$("input:eq(2)").click(function(){
$(":checkbox").removeAttr("checked"); //移除属性checked
$(":radio").removeAttr("checked"); //移除属性checked
$("[value=check2]:checkbox").attr("checked",true);//设置属性checked
$("[value=check3]:checkbox").attr("checked",true);//设置属性checked
$("[value=radio2]:radio").attr("checked",true);//设置属性checked
});
});
</script>
</head>
<body>
<input type="button" value="设置单选下拉框选中"/>
<input type="button" value="设置多选下拉框选中"/>
<input type="button" value="设置单选框和多选框选中"/>
<br/><br/>
<select id="single">
<option>选择1号</option>
<option>选择2号</option>
<option>选择3号</option>
</select>
<select id="multiple" multiple="multiple" style="height:120px;">
<option selected="selected">选择1号</option>
<option>选择2号</option>
<option>选择3号</option>
<option>选择4号</option>
<option selected="selected">选择5号</option>
</select>
<br/><br/>
<input type="checkbox" value="check1"/> 多选1
<input type="checkbox" value="check2"/> 多选2
<input type="checkbox" value="check3"/> 多选3
<input type="checkbox" value="check4"/> 多选4
<br/>
<input type="radio" value="radio1" name="a"/> 单选1
<input type="radio" value="radio2" name="a"/> 单选2
<input type="radio" value="radio3" name="a"/> 单选3
</body>
</html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css">
.high{
font-weight:bold; /* 粗体字 */
color : red; /* 字体颜色设置红色*/
}
.another{
font-style:italic;
color:blue;
}
</style>
<!-- 引入jQuery -->
<script src="../../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){
//获取样式
$("input:eq(0)").click(function(){
alert( $("p").attr("class") );
});
//设置样式
$("input:eq(1)").click(function(){
$("p").attr("class","high");
});
//追加样式
$("input:eq(2)").click(function(){
$("p").addClass("another");
});
//删除全部样式
$("input:eq(3)").click(function(){
$("p").removeClass();
});
//删除指定样式
$("input:eq(4)").click(function(){
$("p").removeClass("high");
});
//重复切换样式
$("input:eq(5)").click(function(){
$("p").toggleClass("another");
});
//判断元素是否含有某样式
$("input:eq(6)").click(function(){
alert( $("p").hasClass("another") )
alert( $("p").is(".another") )
});
});
</script>
</head>
<body>
<input type="button" value="输出class类"/>
<input type="button" value="设置class类"/>
<input type="button" value="追加class类"/>
<input type="button" value="删除全部class类"/>
<input type="button" value="删除指定class类"/>
<input type="button" value="重复切换class类"/>
<input type="button" value="判断元素是否含有某个class类"/>
<p class="myClass" title="选择你最喜欢的水果." >你最喜欢的水果是?</p>
<ul>
<li title='苹果'>苹果</li>
<li title='橘子'>橘子</li>
<li title='菠萝'>菠萝</li>
</ul>
</body>
</html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css">
.test{
font-weight:bold;
color : red;
}
.add{
font-style:italic;
}
</style>
<script src="../../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){
//获取<p>元素的color
$("input:eq(0)").click(function(){
alert( $("p").css("color") );
});
//设置<p>元素的color
$("input:eq(1)").click(function(){
$("p").css("color","red")
});
//设置<p>元素的fontSize和backgroundColor
$("input:eq(2)").click(function(){
$("p").css({"fontSize":"30px" ,"backgroundColor":"#888888"})
});
//获取<p>元素的高度
$("input:eq(3)").click(function(){
alert( $("p").height() );
});
//获取<p>元素的宽度
$("input:eq(4)").click(function(){
alert( $("p").width() );
});
//获取<p>元素的高度
$("input:eq(5)").click(function(){
$("p").height("100px");
});
//获取<p>元素的宽度
$("input:eq(6)").click(function(){
$("p").width("400px");
});
//获取<p>元素的的左边距和上边距
$("input:eq(7)").click(function(){
var offset = $("p").offset();
var left = offset.left;
var top = offset.top;
alert("left:"+left+";top:"+top);
});
});
</script>
</head>
<body>
<input type="button" value="获取<p>元素的color"/>
<input type="button" value="设置<p>元素的color"/>
<input type="button" value="设置<p>元素的fontSize和backgroundColor"/>
<input type="button" value="获取<p>元素的高度"/>
<input type="button" value="获取<p>元素的宽度"/>
<input type="button" value="设置<p>元素的高度"/>
<input type="button" value="设置<p>元素的宽度"/>
<input type="button" value="获取<p>元素的的左边距和上边距"/>
<p title="选择你最喜欢的水果."><strong>你最喜欢的水果是?</strong></p>
<ul>
<li title='苹果'>苹果</li>
<li title='橘子'>橘子</li>
<li title='菠萝'>菠萝</li>
</ul>
</body>
</html>
替换节点
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="../../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){
$("p").replaceWith("<strong>你最不喜欢的水果是?</strong>");
// 同样的实现: $("<strong>你最不喜欢的水果是?</strong>").replaceAll("p");
});
</script>
</head>
<body>
<p title="选择你最喜欢的水果." >你最喜欢的水果是?</p>
<ul>
<li title='苹果'>苹果</li>
<li title='橘子'>橘子</li>
<li title='菠萝'>菠萝</li>
</ul>
</body>
</html>
属性操作
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="../../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){
//设置<p>元素的属性'title'
$("input:eq(0)").click(function(){
$("p").attr("title","选择你最喜欢的水果.");
});
//获取<p>元素的属性'title'
$("input:eq(1)").click(function(){
alert( $("p").attr("title") );
});
//删除<p>元素的属性'title'
$("input:eq(2)").click(function(){
$("p").removeAttr("title");
});
});
</script>
</head>
<body>
<input type="button" value="设置<p>元素的属性'title'"/>
<input type="button" value="获取<p>元素的属性'title'"/>
<input type="button" value="删除<p>元素的属性'title'"/>
<p title="选择你最喜欢的水果." >你最喜欢的水果是?</p>
<ul>
<li title='苹果'>苹果</li>
<li title='橘子'>橘子</li>
<li title='菠萝'>菠萝</li>
</ul>
</body>
</html>
删除节点
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="../../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){
var $li = $("ul li:eq(1)").remove(); // 获取第二个<li>元素节点后,将它从网页中删除。
$li.appendTo("ul"); // 把刚才删除的又重新添加到<ul>元素里
//所以,删除只是从网页中删除,在jQuery对象中,这个元素还是存在的,我们可以重新获取它
$("ul li").remove("li[title!=菠萝]"); //把<li>元素中属性title不等于"菠萝"的<li>元素删除
$("ul li:eq(1)").empty(); // 找到第二个<li>元素节点后,清空此元素里的内容
});
</script>
</head>
<body>
<p title="选择你最喜欢的水果." >你最喜欢的水果是?</p>
<ul>
<li title='苹果'>苹果</li>
<li title='橘子'>橘子</li>
<li title='菠萝'>菠萝</li>
</ul>
</body>
</html>
复制节点
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="../../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){
$("ul li").click(function(){
$(this).clone(true).appendTo("ul"); //
//注意参数true可以复制自己,并且他的副本也有同样功能。
})
});
</script>
</head>
<body>
<p title="选择你最喜欢的水果." >你最喜欢的水果是?</p>
<ul>
<li title='苹果'>苹果</li>
<li title='橘子'>橘子</li>
<li title='菠萝'>菠萝</li>
</ul>
</body>
</html>
插入节点
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="../../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){
var $li_1 = $("<li title='香蕉'>香蕉</li>"); // 创建第一个<li>元素
var $li_2 = $("<li title='雪梨'>雪梨</li>"); // 创建第二个<li>元素
var $li_3 = $("<li title='其它'>其它</li>"); // 创建第三个<li>元素
var $parent = $("ul"); // 获取<ul>节点,即<li>的父节点
var $two_li = $("ul li:eq(1)"); // 获取<ul>节点中第二个<li>元素节点
$parent.append($li_1); // append方法将创建的第一个<li>元素添加到父元素的最后面
$parent.prepend($li_2); // prepend方法将创建的第二个<li>元素添加到父元素里的最前面
$li_3.insertAfter($two_li); // insertAfter方法将创建的第三个<li>元素元素插入到获取的<li>之后
});
</script>
</head>
<body>
<p title="选择你最喜欢的水果." >你最喜欢的水果是?</p>
<ul>
<li title='苹果'>苹果</li>
<li title='橘子'>橘子</li>
<li title='菠萝'>菠萝</li>
</ul>
</body>
</html>
移动节点
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="../../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){
var $one_li = $("ul li:eq(1)"); // 获取<ul>节点中第二个<li>元素节点
var $two_li = $("ul li:eq(2)"); // 获取<ul>节点中第三个<li>元素节点
$two_li.insertBefore($one_li); //移动节点
});
</script>
</head>
<body>
<p title="选择你最喜欢的水果." >你最喜欢的水果是?</p>
<ul>
<li title='苹果'>苹果</li>
<li title='橘子'>橘子</li>
<li title='菠萝'>菠萝</li>
</ul>
</body>
</html>
得到元素的值
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="../../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){
var $para = $("p"); // 获取<p>节点
var $li = $("ul li:eq(1)"); // 获取第二个<li>元素节点
var p_txt = $para.attr("title"); // 输出<p>元素节点属性title
var ul_txt = $li.attr("title"); // 获取<ul>里的第二个<li>元素节点的属性title
var li_txt = $li.text(); // 输出第二个<li>元素节点的text
alert(p_txt);
alert(ul_txt);
alert(li_txt);
});
</script>
</head>
<body>
<p title="选择你最喜欢的水果." >你最喜欢的水果是?</p>
<ul>
<li title='苹果'>苹果</li>
<li title='橘子'>橘子</li>
<li title='菠萝'>菠萝</li>
</ul>
</body>
</html>
创建节点
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>3-2-3</title>
<!-- 引入jQuery -->
<script src="../../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){
var $li_1 = $("<li title='香蕉'>香蕉</li>"); //创建一个<li>元素
//包括元素节点,文本节点和属性节点
//其中title='香蕉' 就是创建的属性节点
var $li_2 = $("<li title='雪梨'>雪梨</li>"); //创建一个<li>元素
//包括元素节点,文本节点和属性节点
//其中title='雪梨' 就是创建的属性节点
var $parent = $("ul"); // 获取<ul>节点。<li>的父节点
$parent.append($li_1); // 添加到<ul>节点中,使之能在网页中显示
$parent.append($li_2); // 等价于:$parent.append($li_1).append($li_2);
});
</script>
</head>
<body>
<p title="选择你最喜欢的水果." >你最喜欢的水果是?</p>
<ul>
<li title='苹果'>苹果</li>
<li title='橘子'>橘子</li>
<li title='菠萝'>菠萝</li>
</ul>
</body>
</html>
1.在lib中加入相应的dwr.jar包
2.在web.xml中加入以下代码:
<servlet>
<servlet-name>dwr-invoker</servlet-name>
<servlet-class>
org.directwebremoting.servlet.DwrServlet
</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>dwr-invoker</servlet-name>
<url-pattern>/dwr/*</url-pattern>
</servlet-mapping>
3.在web-inf目录下新建dwr.xml文件,加入一个简单的配置:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 2.0//EN" "http://www.getahead.ltd.uk/dwr/dwr20.dtd">
<dwr>
<allow>
<create creator="new" javascript="service">
<param name="class" value="helloWorld.Service"/>
</create>
</allow>
</dwr>
4.新建一个servlet类,
public class Service {
public String sayHello(String yourName){
return yourName;
}
}
5.新建一个jsp页面如下:
<html>
<head>
<title>My JSP 'index.jsp' starting page</title>
<script type='text/javascript' src='/dwr2/dwr/interface/service.js'></script>
<script type='text/javascript' src='/dwr2/dwr/engine.js'></script>
<script type='text/javascript' src='/dwr2/dwr/util.js'></script>
<script type="text/javascript">
function firstdwr(){
service.sayHello("yangjunwei",callback);
}
function callback(d){
alert(d);
}
</script>
</head>
<body>
<input type="button" onclick="firstdwr()"/>
</body>
</html>
当点击按钮时,就会弹出yangjunwei,这就完成了一个简单的dwrajax交互
public class HttpRequestDeviceUtils {
/**Wap网关Via头信息中特有的描述信息*/
private static String mobileGateWayHeaders[]=new String[]{
"ZXWAP",//中兴提供的wap网关的via信息,例如:Via=ZXWAP GateWayZTE Technologies,
"chinamobile.com",//中国移动的诺基亚wap网关,例如:Via=WTP/1.1 GDSZ-PB-GW003-WAP07.gd.chinamobile.com (Nokia WAP Gateway 4.1 CD1/ECD13_D/4.1.04)
"monternet.com",//移动梦网的网关,例如:Via=WTP/1.1 BJBJ-PS-WAP1-GW08.bj1.monternet.com. (Nokia WAP Gateway 4.1 CD1/ECD13_E/4.1.05)
"infoX",//华为提供的wap网关,例如:Via=HTTP/1.1 GDGZ-PS-GW011-WAP2 (infoX-WISG Huawei Technologies),或Via=infoX WAP Gateway V300R001 Huawei Technologies
"XMS 724Solutions HTG",//国外电信运营商的wap网关,不知道是哪一家
"wap.lizongbo.com",//自己测试时模拟的头信息
"Bytemobile",//貌似是一个给移动互联网提供解决方案提高网络运行效率的,例如:Via=1.1 Bytemobile OSN WebProxy/5.1
};
/**电脑上的IE或Firefox浏览器等的User-Agent关键词*/
private static String[] pcHeaders=new String[]{
"Windows 98",
"Windows ME",
"Windows 2000",
"Windows XP",
"Windows NT",
"Ubuntu"
};
/**手机浏览器的User-Agent里的关键词*/
private static String[] mobileUserAgents=new String[]{
"Nokia",//诺基亚,有山寨机也写这个的,总还算是手机,Mozilla/5.0 (Nokia5800 XpressMusic)UC AppleWebkit(like Gecko) Safari/530
"SAMSUNG",//三星手机 SAMSUNG-GT-B7722/1.0+SHP/VPP/R5+Dolfin/1.5+Nextreaming+SMM-MMS/1.2.0+profile/MIDP-2.1+configuration/CLDC-1.1
"MIDP-2",//j2me2.0,Mozilla/5.0 (SymbianOS/9.3; U; Series60/3.2 NokiaE75-1 /110.48.125 Profile/MIDP-2.1 Configuration/CLDC-1.1 ) AppleWebKit/413 (KHTML like Gecko) Safari/413
"CLDC1.1",//M600/MIDP2.0/CLDC1.1/Screen-240X320
"SymbianOS",//塞班系统的,
"MAUI",//MTK山寨机默认ua
"UNTRUSTED/1.0",//疑似山寨机的ua,基本可以确定还是手机
"Windows CE",//Windows CE,Mozilla/4.0 (compatible; MSIE 6.0; Windows CE; IEMobile 7.11)
"iPhone",//iPhone是否也转wap?不管它,先区分出来再说。Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_1 like Mac OS X; zh-cn) AppleWebKit/532.9 (KHTML like Gecko) Mobile/8B117
"iPad",//iPad的ua,Mozilla/5.0 (iPad; U; CPU OS 3_2 like Mac OS X; zh-cn) AppleWebKit/531.21.10 (KHTML like Gecko) Version/4.0.4 Mobile/7B367 Safari/531.21.10
"Android",//Android是否也转wap?Mozilla/5.0 (Linux; U; Android 2.1-update1; zh-cn; XT800 Build/TITA_M2_16.22.7) AppleWebKit/530.17 (KHTML like Gecko) Version/4.0 Mobile Safari/530.17
"BlackBerry",//BlackBerry8310/2.7.0.106-4.5.0.182
"UCWEB",//ucweb是否只给wap页面? Nokia5800 XpressMusic/UCWEB7.5.0.66/50/999
"ucweb",//小写的ucweb貌似是uc的代理服务器Mozilla/6.0 (compatible; MSIE 6.0;) Opera ucweb-squid
"BREW",//很奇怪的ua,例如:REW-Applet/0x20068888 (BREW/3.1.5.20; DeviceId: 40105; Lang: zhcn) ucweb-squid
"J2ME",//很奇怪的ua,只有J2ME四个字母
"YULONG",//宇龙手机,YULONG-CoolpadN68/10.14 IPANEL/2.0 CTC/1.0
"YuLong",//还是宇龙
"COOLPAD",//宇龙酷派YL-COOLPADS100/08.10.S100 POLARIS/2.9 CTC/1.0
"TIANYU",//天语手机TIANYU-KTOUCH/V209/MIDP2.0/CLDC1.1/Screen-240X320
"TY-",//天语,TY-F6229/701116_6215_V0230 JUPITOR/2.2 CTC/1.0
"K-Touch",//还是天语K-Touch_N2200_CMCC/TBG110022_1223_V0801 MTK/6223 Release/30.07.2008 Browser/WAP2.0
"Haier",//海尔手机,Haier-HG-M217_CMCC/3.0 Release/12.1.2007 Browser/WAP2.0
"DOPOD",//多普达手机
"Lenovo",// 联想手机,Lenovo-P650WG/S100 LMP/LML Release/2010.02.22 Profile/MIDP2.0 Configuration/CLDC1.1
"LENOVO",// 联想手机,比如:LENOVO-P780/176A
"HUAQIN",//华勤手机
"AIGO-",//爱国者居然也出过手机,AIGO-800C/2.04 TMSS-BROWSER/1.0.0 CTC/1.0
"CTC/1.0",//含义不明
"CTC/2.0",//含义不明
"CMCC",//移动定制手机,K-Touch_N2200_CMCC/TBG110022_1223_V0801 MTK/6223 Release/30.07.2008 Browser/WAP2.0
"DAXIAN",//大显手机DAXIAN X180 UP.Browser/6.2.3.2(GUI) MMP/2.0
"MOT-",//摩托罗拉,MOT-MOTOROKRE6/1.0 LinuxOS/2.4.20 Release/8.4.2006 Browser/Opera8.00 Profile/MIDP2.0 Configuration/CLDC1.1 Software/R533_G_11.10.54R
"SonyEricsson",// 索爱手机,SonyEricssonP990i/R100 Mozilla/4.0 (compatible; MSIE 6.0; Symbian OS; 405) Opera 8.65 [zh-CN]
"GIONEE",//金立手机
"HTC",//HTC手机
"ZTE",//中兴手机,ZTE-A211/P109A2V1.0.0/WAP2.0 Profile
"HUAWEI",//华为手机,
"webOS",//palm手机,Mozilla/5.0 (webOS/1.4.5; U; zh-CN) AppleWebKit/532.2 (KHTML like Gecko) Version/1.0 Safari/532.2 Pre/1.0
"GoBrowser",//3g GoBrowser.User-Agent=Nokia5230/GoBrowser/2.0.290 Safari
"IEMobile",//Windows CE手机自带浏览器,
"WAP2.0"//支持wap 2.0的
};
/**
* 根据当前请求的特征,判断该请求是否来自手机终端,主要检测特殊的头信息,以及user-Agent这个header
* @param request http请求
* @return 如果命中手机特征规则,则返回对应的特征字符串
*/
public static boolean isMobileDevice(HttpServletRequest request){
boolean b = false;
boolean pcFlag = false;
boolean mobileFlag = false;
String via = request.getHeader("Via");
String userAgent = request.getHeader("user-agent");
for (int i = 0; via!=null && !via.trim().equals("") && i < mobileGateWayHeaders.length; i++) {
if(via.contains(mobileGateWayHeaders[i])){
mobileFlag = true;
break;
}
}
for (int i = 0;!mobileFlag && userAgent!=null && !userAgent.trim().equals("") && i < mobileUserAgents.length; i++) {
if(userAgent.contains(mobileUserAgents[i])){
mobileFlag = true;
break;
}
}
for (int i = 0; userAgent!=null && !userAgent.trim().equals("") && i < pcHeaders.length; i++) {
if(userAgent.contains(pcHeaders[i])){
pcFlag = true;
break;
}
}
if(mobileFlag==true && pcFlag==false){
b=true;
}
return b;//false pc true shouji
}
}
可以写一个类继承Handler类,拦截所有的请求,得到url,根据请求头的信息判断出是手机访问还是电脑访问,根据需求跳转到不同的页面或者方法中
<html>
<head>
<script>
function hello(){
alert("hello");
}
function byee(){
alert("bye");
}
function show(){
var v = document.myform.inname.value;
var p = document.myform.pwd.value;
alert(v+p);
}
function valia(f){
var v = document.myform.inname.value;
var p = document.myform.pwd.value;
return true;
}
</script>
</head>
<body onload="hello()" onUnLoad="byee()" >
<form action="dd" name="myform" onsubmit="return valia(this) ">
<input type="text" name="inname" />
<input type="text" name="pwd" />
<input type="submit" />
</form>
</body>
</html>
判断应该属于程序部分的处理,不属于
前端的范畴,是靠判断请求头信息(HTTP_USER_AGENT)进行判断的。
步骤是:1.
首先需要安装三个Firefox插件:wmlbrowser、XHTML Mobile Profile、User Agent Switcher;(我称它们为“伪娘三贱客”)
2.
安装好后需要设置 User Agent Switcher ,点击菜单 工具 → Default User Agent → User Agent Switcher → Options → New→New User Agent... ,Description是你给它的一个称呼,比如小三,凹凸曼等等。关键的部分是User Agent里面的东西(这里是请求头主要的信息,程序会根据这个请求头进行判断你是否是手持设备),这里就需要把我们想要模拟的手持设备的信息填入了。
3.
添加好后一路确定,回到浏览器界面。工具 →default user agent →选择你自己添加的那个 →在浏览器地址输入你想要访问的地址即可。
十分大方这里你会看到几个选项,Default User Agent (浏览器默认的信息),Internet Explorer (可以模拟ie6,7,8的头信息),Search Robots (模拟谷歌,雅虎,msn的蜘蛛),iphone 3.0 (默认存在的一个)
4.
下面列出几个比较常见手机的User Agent:(如果想要查询更多的手机user agent 信息的话,
去看这里,
还有这里)
iPhone3:
Mozilla/5.0 (iPhone; U; CPU iPhone OS 3_0 like Mac OS X; en-us) AppleWebKit/528.18 (KHTML, like Gecko) Version/4.0 Mobile/7A341 Safari/528.16
Android:
Mozilla/5.0 (Linux; U; Android 2.2; en-us; Nexus One Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1
诺基亚N95:
Mozilla/5.0 (SymbianOS/9.2; U; Series60/3.1 NokiaN95/30.0.015; Profile MIDP-2.0 Configuration/CLDC-1.1) AppleWebKit/413 (KHTML, like Gecko) Safari/413
诺基亚N97:
Mozilla/5.0 (SymbianOS/9.4; Series60/5.0 NokiaN97-1/20.0.019; Profile/MIDP-2.1 Configuration/CLDC-1.1) AppleWebKit/525 (KHTML, like Gecko) BrowserNG/7.1.18124
package pc;
import javax.servlet.http.HttpServletRequest;
public class HttpRequestDeviceUtils {
/**Wap网关Via头信息中特有的描述信息*/
private static String mobileGateWayHeaders[]=new String[]{
"ZXWAP",//中兴提供的wap网关的via信息,例如:Via=ZXWAP GateWayZTE Technologies,
"chinamobile.com",//中国移动的诺基亚wap网关,例如:Via=WTP/1.1 GDSZ-PB-GW003-WAP07.gd.chinamobile.com (Nokia WAP Gateway 4.1 CD1/ECD13_D/4.1.04)
"monternet.com",//移动梦网的网关,例如:Via=WTP/1.1 BJBJ-PS-WAP1-GW08.bj1.monternet.com. (Nokia WAP Gateway 4.1 CD1/ECD13_E/4.1.05)
"infoX",//华为提供的wap网关,例如:Via=HTTP/1.1 GDGZ-PS-GW011-WAP2 (infoX-WISG Huawei Technologies),或Via=infoX WAP Gateway V300R001 Huawei Technologies
"XMS 724Solutions HTG",//国外电信运营商的wap网关,不知道是哪一家
"wap.lizongbo.com",//自己测试时模拟的头信息
"Bytemobile",//貌似是一个给移动互联网提供解决方案提高网络运行效率的,例如:Via=1.1 Bytemobile OSN WebProxy/5.1
};
/**电脑上的IE或Firefox浏览器等的User-Agent关键词*/
private static String[] pcHeaders=new String[]{
"Windows 98",
"Windows ME",
"Windows 2000",
"Windows XP",
"Windows NT",
"Ubuntu"
};
/**手机浏览器的User-Agent里的关键词*/
private static String[] mobileUserAgents=new String[]{
"Nokia",//诺基亚,有山寨机也写这个的,总还算是手机,Mozilla/5.0 (Nokia5800 XpressMusic)UC AppleWebkit(like Gecko) Safari/530
"SAMSUNG",//三星手机 SAMSUNG-GT-B7722/1.0+SHP/VPP/R5+Dolfin/1.5+Nextreaming+SMM-MMS/1.2.0+profile/MIDP-2.1+configuration/CLDC-1.1
"MIDP-2",//j2me2.0,Mozilla/5.0 (SymbianOS/9.3; U; Series60/3.2 NokiaE75-1 /110.48.125 Profile/MIDP-2.1 Configuration/CLDC-1.1 ) AppleWebKit/413 (KHTML like Gecko) Safari/413
"CLDC1.1",//M600/MIDP2.0/CLDC1.1/Screen-240X320
"SymbianOS",//塞班系统的,
"MAUI",//MTK山寨机默认ua
"UNTRUSTED/1.0",//疑似山寨机的ua,基本可以确定还是手机
"Windows CE",//Windows CE,Mozilla/4.0 (compatible; MSIE 6.0; Windows CE; IEMobile 7.11)
"iPhone",//iPhone是否也转wap?不管它,先区分出来再说。Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_1 like Mac OS X; zh-cn) AppleWebKit/532.9 (KHTML like Gecko) Mobile/8B117
"iPad",//iPad的ua,Mozilla/5.0 (iPad; U; CPU OS 3_2 like Mac OS X; zh-cn) AppleWebKit/531.21.10 (KHTML like Gecko) Version/4.0.4 Mobile/7B367 Safari/531.21.10
"Android",//Android是否也转wap?Mozilla/5.0 (Linux; U; Android 2.1-update1; zh-cn; XT800 Build/TITA_M2_16.22.7) AppleWebKit/530.17 (KHTML like Gecko) Version/4.0 Mobile Safari/530.17
"BlackBerry",//BlackBerry8310/2.7.0.106-4.5.0.182
"UCWEB",//ucweb是否只给wap页面? Nokia5800 XpressMusic/UCWEB7.5.0.66/50/999
"ucweb",//小写的ucweb貌似是uc的代理服务器Mozilla/6.0 (compatible; MSIE 6.0;) Opera ucweb-squid
"BREW",//很奇怪的ua,例如:REW-Applet/0x20068888 (BREW/3.1.5.20; DeviceId: 40105; Lang: zhcn) ucweb-squid
"J2ME",//很奇怪的ua,只有J2ME四个字母
"YULONG",//宇龙手机,YULONG-CoolpadN68/10.14 IPANEL/2.0 CTC/1.0
"YuLong",//还是宇龙
"COOLPAD",//宇龙酷派YL-COOLPADS100/08.10.S100 POLARIS/2.9 CTC/1.0
"TIANYU",//天语手机TIANYU-KTOUCH/V209/MIDP2.0/CLDC1.1/Screen-240X320
"TY-",//天语,TY-F6229/701116_6215_V0230 JUPITOR/2.2 CTC/1.0
"K-Touch",//还是天语K-Touch_N2200_CMCC/TBG110022_1223_V0801 MTK/6223 Release/30.07.2008 Browser/WAP2.0
"Haier",//海尔手机,Haier-HG-M217_CMCC/3.0 Release/12.1.2007 Browser/WAP2.0
"DOPOD",//多普达手机
"Lenovo",// 联想手机,Lenovo-P650WG/S100 LMP/LML Release/2010.02.22 Profile/MIDP2.0 Configuration/CLDC1.1
"LENOVO",// 联想手机,比如:LENOVO-P780/176A
"HUAQIN",//华勤手机
"AIGO-",//爱国者居然也出过手机,AIGO-800C/2.04 TMSS-BROWSER/1.0.0 CTC/1.0
"CTC/1.0",//含义不明
"CTC/2.0",//含义不明
"CMCC",//移动定制手机,K-Touch_N2200_CMCC/TBG110022_1223_V0801 MTK/6223 Release/30.07.2008 Browser/WAP2.0
"DAXIAN",//大显手机DAXIAN X180 UP.Browser/6.2.3.2(GUI) MMP/2.0
"MOT-",//摩托罗拉,MOT-MOTOROKRE6/1.0 LinuxOS/2.4.20 Release/8.4.2006 Browser/Opera8.00 Profile/MIDP2.0 Configuration/CLDC1.1 Software/R533_G_11.10.54R
"SonyEricsson",// 索爱手机,SonyEricssonP990i/R100 Mozilla/4.0 (compatible; MSIE 6.0; Symbian OS; 405) Opera 8.65 [zh-CN]
"GIONEE",//金立手机
"HTC",//HTC手机
"ZTE",//中兴手机,ZTE-A211/P109A2V1.0.0/WAP2.0 Profile
"HUAWEI",//华为手机,
"webOS",//palm手机,Mozilla/5.0 (webOS/1.4.5; U; zh-CN) AppleWebKit/532.2 (KHTML like Gecko) Version/1.0 Safari/532.2 Pre/1.0
"GoBrowser",//3g GoBrowser.User-Agent=Nokia5230/GoBrowser/2.0.290 Safari
"IEMobile",//Windows CE手机自带浏览器,
"WAP2.0"//支持wap 2.0的
};
/**
* 根据当前请求的特征,判断该请求是否来自手机终端,主要检测特殊的头信息,以及user-Agent这个header
* @param request http请求
* @return 如果命中手机特征规则,则返回对应的特征字符串
*/
public static boolean isMobileDevice(HttpServletRequest request){
boolean b = false;
boolean pcFlag = false;
boolean mobileFlag = false;
String via = request.getHeader("Via");
String userAgent = request.getHeader("user-agent");
for (int i = 0; via!=null && !via.trim().equals("") && i < mobileGateWayHeaders.length; i++) {
if(via.contains(mobileGateWayHeaders[i])){
mobileFlag = true;
break;
}
}
for (int i = 0;!mobileFlag && userAgent!=null && !userAgent.trim().equals("") && i < mobileUserAgents.length; i++) {
if(userAgent.contains(mobileUserAgents[i])){
mobileFlag = true;
break;
}
}
for (int i = 0; userAgent!=null && !userAgent.trim().equals("") && i < pcHeaders.length; i++) {
if(userAgent.contains(pcHeaders[i])){
pcFlag = true;
break;
}
}
if(mobileFlag==true && pcFlag==false){
b=true;
}
return b;//false pc true shouji
}
}
public static List<String> getWeekDay(String strDate) {
List<String> list = new ArrayList<String>();//第几周,周几
String nReturn = null;
Calendar c = Calendar.getInstance(); // 实例化一个Calendar对象
c.clear(); // 清空Calendar
c.set(Integer.parseInt(strDate.substring(0, 4)), Integer
.parseInt(strDate.substring(5, 7)) - 1, Integer
.parseInt(strDate.substring(8, 10))); // 设置这个日期的内容
System.out.println("------------" + c.get(Calendar.YEAR) + "年" + (c.get(Calendar.MONTH) + 1) + "月"+(c.get(Calendar.DATE))+"日的天数和周数-------------");
System.out.println("天数:" + c.getActualMaximum(Calendar.DAY_OF_MONTH));
System.out.println("周数:" + c.getActualMaximum(Calendar.WEEK_OF_MONTH));
System.out.println("第几周:"+c.get(Calendar.DAY_OF_WEEK_IN_MONTH));
switch (c.get(Calendar.DAY_OF_WEEK)) {
case 1:
nReturn = "7";
break;
case 2:
nReturn = "1";
break;
case 3:
nReturn = "2";
break;
case 4:
nReturn = "3";
break;
case 5:
nReturn = "4";
break;
case 6:
nReturn = "5";
break;
case 7:
nReturn = "6";
break;
default:
nReturn = null;
break;
}
list.add(String.valueOf(c.get(Calendar.DAY_OF_WEEK_IN_MONTH)));
list.add(nReturn);
return list;
}
先要在exporting.js中修改导出图片的url是本地的服务器地址
String type = getPara("type");//getRequest().getParameter("type");
String svg =getPara("svg");// getRequest().getParameter("svg");
String filename = getPara("filename");//getRequest().getParameter("filename");
ServletOutputStream out1 = null;
try {
//getRequest().setCharacterEncoding("utf-8");
System.out.println(type);
System.out.println(svg);
System.out.println(filename);
filename = filename==null?"chart":filename;
out1 = getResponse().getOutputStream();
if (null != type && null != svg) {
svg = svg.replaceAll(":rect", "rect");
String ext = "";
Transcoder t = null;
if (type.equals("image/png")) {
ext = "png";
t = new PNGTranscoder();
} else if (type.equals("image/jpeg")) {
ext = "jpg";
t = new JPEGTranscoder();
} else if(type.equals("image/svg+xml")) {
ext = "svg";
}else if(type.equals("application/pdf")){
t = new PDFTranscoder();
ext = "pdf";
}
getResponse().addHeader("Content-Disposition", "attachment; filename="+ filename + "."+ext);
getResponse().addHeader("Content-Type", type);
if (null != t) {
TranscoderInput input = new TranscoderInput(new StringReader(svg));
TranscoderOutput output = new TranscoderOutput(out1);
try {
t.transcode(input, output);
} catch (TranscoderException e) {
out1.print("Problem transcoding stream. See the web logs for more details.");
e.printStackTrace();
}
} else if (ext.equals("svg")) {
// out.print(svg);
OutputStreamWriter writer = new OutputStreamWriter(out1, "UTF-8");
writer.append(svg);
writer.flush();
writer.close();
} /*else
out.print("Invalid type: " + type);*/
} else {
//getResponse().addHeader("Content-Type", "text/html");
// out.println("Usage:\n\tParameter [svg]: The DOM Element to be converted." +
// "\n\tParameter [type]: The destination MIME type for the elment to be transcoded.");
}
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
out1.flush();
getResponse().flushBuffer();
out1.close();
} catch (Exception e2) {
}
}
需要的jar包:
Ext.namespace('Ext.ux');
Ext.ux.EmRealtimeDisplayPanel = function(treeNode, panelId, config) {
this.treeNode = treeNode;
this.panelId = panelId;
var temhum = new Ext.form.ComboBox({
name : 'temhunm',
fieldLabel : '状态',
allowBlank : false,
blankText : '请选择温湿度',
editable : false,
triggerAction : 'all',//all表示把下拉框列表框的列表值全部显示出来
store : new Ext.data.ArrayStore({
fields : [ 'name', 'value' ],
data : [ [ '温度', '1' ], [ '湿度', '2' ] ]
}),
mode : 'local',
displayField : 'name',
valueField : 'value',
width : 60
});
var storenode = new Ext.data.JsonStore({ //读配置文件
autoLoad:true,
url : path+"/wenshi/getnode",
root : "options",
fields : [ {
name : 'name'
}]
});
var node = new Ext.form.ComboBox({
fieldLabel : '节点',
allowBlank : false,
blankText : '请选择节点',
editable : false,
triggerAction : 'all',
store : storenode,
mode : 'local',
displayField : 'name',
valueField : 'name',
width : 60
});
var dataArr = new Array();
var store = new Ext.data.ArrayStore({
fields: ['data', 'time'],
data: dataArr
});
var varNodeId = '';//节点的id值
var taskStart = false;
//定时器里面的参数配置
var task = {
run: function(){
gridStore.load({
params: {
'nodeid' : varNodeId,
'tem' :th
},
callback:function(r){
if(!(typeof(r[0])==='undefined')) {
dataArr.push([r[0].data.data, r[0].data.time]);
store.loadData(dataArr);
}
}
});
},
interval: 3000
};
var gridStore= new Ext.data.JsonStore({
fields:['time', 'data'],
autoLoad:true,
baseParams : {
'nodeid' : "",
'tem' :""
},
url :path+'/wenshi/getShishiData',
root : "data"
});
var panel1= new Ext.Panel({
title: '实时曲线图显示',
width: 700,
height: 400,
smooth: true,
type: 'circle',
items: {
xtype: 'linechart',
url: 'extjs3/resources/charts.swf',
store: store,
xField: 'time',
yField: 'data',
xAxis: new Ext.chart.CategoryAxis({
title: '时间(秒)'//00 09:00 分钟 秒:毫秒
}),
yAxis: new Ext.chart.NumericAxis({
title: '数值'
})
},
tbar : [
{
xtype : 'label',
text : '请选择节点: '
},
node, {
xtype : 'label',
text : '请选择温湿度: '
},
temhum,
{
text : '查询',
handler : function(btn, event) {
var nodeid = node.getValue();
var tem = temhum.getValue();
if (nodeid == undefined || nodeid == ''||tem==''){
return;
} else {
dataArr = new Array();
varNodeId = nodeid;
th = tem;
// alert(th);
if(!taskStart) {
Ext.TaskMgr.start(task);//定时执行代码
taskStart =true;
}
}
}
}]
});
Ext.ux.EmRealtimeDisplayPanel.superclass.constructor.call(this, {
id : this.panelId,
title : this.treeNode.text,
layout : 'fit',
closable : true,
preventBodyReset : true,
items : [panel1]
});
};
Ext.extend(Ext.ux.EmRealtimeDisplayPanel, Ext.Panel, {});
Ext.reg('emEmRealtimeDisplayPanel', Ext.ux.EmRealtimeDisplayPanel);
Ext.namespace('Ext.ux');
Ext.ux.WaterRealtimeDisplayPanel = function(treeNode, panelId, config) {
this.treeNode = treeNode;
this.panelId = panelId;
var series=[{"name":"实时数据显示","data":[]}];
var temhum = new Ext.form.ComboBox({
name : 'temhunm',
fieldLabel : '状态',
allowBlank : false,
blankText : '请选择温湿度',
editable : false,
triggerAction : 'all',//all表示把下拉框列表框的列表值全部显示出来
store : new Ext.data.ArrayStore({
fields : [ 'name', 'value' ],
data : [ [ '温度', '1' ], [ '湿度', '2' ] ]
}),
mode : 'local',
displayField : 'name',
valueField : 'value',
width : 60
});
var storeProvince = new Ext.data.JsonStore({
autoLoad:true,
url : path+"/wenshi/getnode",
root : "options",
fields : [ {
name : 'name'
}]
});
var nodeCtl = new Ext.form.ComboBox({
fieldLabel : '节点',
allowBlank : false,
blankText : '请选择节点',
editable : false,
triggerAction : 'all',
store : storeProvince,
mode : 'local',
displayField : 'name',
valueField : 'name',
width : 140
});
var stTime = new Ext.form.DateField({
fieldLabel : '选择时间',
allowBlank : false,
emptyText : '请选择开始日期',
editable : false,
format : 'Y-m-d',
maxValue : new Date(),
width : 130
});
var data = [
['y','年'],
['m','月'],
['d','日']
// ['w','周']
];
var store = new Ext.data.SimpleStore({
fields: ['value', 'text'],
data: data
});
var combo = new Ext.form.ComboBox({
store: store,
fieldLabel:"请选择时间对应的类型",
emptyText: '请选择筛选类型',
mode: 'local',
triggerAction : 'all',
valueField: 'value',
displayField: 'text'
});
Ext.ux.WaterRealtimeDisplayPanel.superclass.constructor.call(this, {
id : this.panelId,
title : this.treeNode.text,
closable : true,
autoScroll : true,
height : 400,
items:[
{
layout:'column',
border:false,
items:[{
//columnWidth: .25 ,
layout:'form',
border:false,
labelAlign:'right',
width : 200,
labelWidth:40,
items:[
temhum, nodeCtl]
}
,{
layout:'form',
width : 200,
labelWidth:60,
border:false,
labelAlign:'left',
items:[stTime]
},//combo
combo
,
{
layout:'form',
border:false,
scope:this,
items:[{
xtype:'button',
border:false,
width:70,
style:"margin-left:10px",
text:'查询',
scope:this,
handler:function(){
// 获取表单对象
var _params_ = this.getForm().getValues(false);
var nodeid = nodeCtl.getValue();//获取节点id
var checktype=combo.getValue();//选择的筛选类型
var checktime=stTime.getValue();//获取时间的值
var th = temhum.getValue();
if (th == undefined || th == ''){
Ext.Msg.alert("提示","节点不能为空");
return;
}
if (nodeid == undefined || nodeid == ''){
Ext.Msg.alert("提示","节点不能为空");
return;
}
if(!stTime.isValid()){
Ext.Msg.alert('信息', '时间为必选项');
return;
}
if (checktype == undefined || checktype == ''){
Ext.Msg.alert("提示","筛选类型不能为空");
return;
}
// 获得统计【就是显示的那个图】 配置文件对象
var _op_ = this.getOptions();
//首先从后台获得x轴上值
var categories=_op_.xAxis.categories;
categories=[];
$.ajax({
type:"POST", // 提交方式
url:path+'/wenshi/collectHositoryDataName', // 提交地址
dataType:"json", // 解释格式
data:{"nodeid":nodeid,"checktime":checktime.format('Y-m-d'),"checktype":checktype,"th":th}, // 请求参数
success:function(iJson){
var results = eval(iJson); // 转换成 JSON 数据
var r = results[0].data;
for(var i=0;i<r.length;i++){
categories.push(r[i]);
}
_op_.xAxis.categories=categories;
},
error:function(){
Ext.Msg.alert('系统操作','网络不通畅或数据格式不对!');
}
});
// 获得统计 对象的 数据
var _series_ = _op_.series;
// 清空 统计 对象的 数据 重新加载
_series_ = [] ;
// 创建一个统计 对象胡方法
var _createChart_ = function (obj){new Highcharts.Chart(obj);};
// 向后台发送请求
var d = new Ext.util.DelayedTask(function(){
$.ajax({
type:"POST", // 提交方式
url:path+'/wenshi/collectHositoryData', // 提交地址
dataType:"json", // 解释格式
data:{"nodeid":nodeid,"checktime":checktime.format('Y-m-d'),"checktype":checktype,"th":th}, // 请求参数
success:function(iJson){
var results = eval(iJson); // 转换成 JSON 数据
for(var i =0 ; i < results.length;i++){ // 解释和装载数据
_series_.push({name:results[i].name,data:results[i].data});
}
_op_.series = _series_; // 赋值
_createChart_(_op_); // 重新创建一个统计
},
error:function(){
Ext.Msg.alert('系统操作','网络不通畅或数据格式不对!');
}
});
});
d.delay(1000);
}
}]
}]
},
{
xtype:'panel', // 创建 Highcharts 所依赖的 div
html:'<div id="'+"test"+'" style="width:1000px; height: 500px; margin: 0 auto"></div>'
}
],
listeners : {
activate : function(p) {
var obj=this.getOptions();
obj.series=series;
var chart =new Highcharts.Chart(obj);
}
},
getOptions:function(){
return {
chart : {
renderTo :"test",
type: 'spline'
},
lang : {
exportButtonTitle : '导出图表',
printButtonTitle : '打印报表'
},
title : {
text : '节点历史参数曲线图'
},
xAxis : {
title : {
text : '采集时间'
}
,
//categories : ['1秒', '2秒','3秒']//设置x轴上分类名称
},
yAxis : {
title : {
text : '节点参数值'
},
plotLines: [{
value: 0,
width: 1,
color: '#808080'
}]
},
tooltip: {
//enabled: false, //是否显示提示框
formatter: function() {
return "时间:"+this.x +'<br/>'+"参数值:"+ this.y;
}
}
//,
// series : [{
// name : '实时数据显示',
// data : [141, 100, 4]
// }]
};
}
});
};
Ext.extend(Ext.ux.WaterRealtimeDisplayPanel, Ext.FormPanel, {
});
Ext.reg('ljsStudentTuPanel', Ext.ux.WaterRealtimeDisplayPanel);
后台导出图片的方法是:
public class ImageController extends Controller{
public void index(){
String type = getPara("type");
String svg =getPara("svg");
String filename = getPara("filename");
ServletOutputStream out1 = null;
try {
filename = filename==null?"chart":filename;
out1 = getResponse().getOutputStream();
if (null != type && null != svg) {
svg = svg.replaceAll(":rect", "rect");
String ext = "";
Transcoder t = null;
if (type.equals("image/png")) {
ext = "png";
t = new PNGTranscoder();
} else if (type.equals("image/jpeg")) {
ext = "jpg";
t = new JPEGTranscoder();
} else if(type.equals("image/svg+xml")) {
ext = "svg";
}else if(type.equals("application/pdf")){
t = new PDFTranscoder();
ext = "pdf";
}
getResponse().addHeader("Content-Disposition", "attachment; filename="+ filename + "."+ext);
getResponse().addHeader("Content-Type", type);
if (null != t) {
TranscoderInput input = new TranscoderInput(new StringReader(svg));
TranscoderOutput output = new TranscoderOutput(out1);
try {
t.transcode(input, output);
} catch (TranscoderException e) {
out1.print("Problem transcoding stream. See the web logs for more details.");
e.printStackTrace();
}
} else if (ext.equals("svg")) {
OutputStreamWriter writer = new OutputStreamWriter(out1, "UTF-8");
writer.append(svg);
writer.flush();
writer.close();
} else
out1.print("Invalid type: " + type);
} else {
//getResponse().addHeader("Content-Type", "text/html");
// out.println("Usage:\n\tParameter [svg]: The DOM Element to be converted." +
// "\n\tParameter [type]: The destination MIME type for the elment to be transcoded.");
}
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
out1.flush();
getResponse().flushBuffer();
out1.close();
} catch (Exception e2) {
}
}
renderNull();//不跳转
}
}
public static int getDaysByMonth(String time){
Calendar rightNow = Calendar.getInstance();
SimpleDateFormat simpleDate = new SimpleDateFormat("yyyy-MM"); //如果写成年月日的形式的话,要写小d,如:"yyyy/MM/dd"
try {
rightNow.setTime(simpleDate.parse(time)); //要计算你想要的月份,改变这里即可
} catch (Exception e) {
e.printStackTrace();
}
int days = rightNow.getActualMaximum(Calendar.DAY_OF_MONTH);
return days;
}
public static List<String> getWeekDay(String str) {
List<String> list = new ArrayList<String>();
Calendar c = Calendar.getInstance();
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = null;
try {
date = sdf.parse(str);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
c.setTime(date);
int week = c.get(Calendar.WEEK_OF_MONTH);//获取是本月的第几周
System.out.println("今天是本月的第" + week + "周");
String nReturn;
switch (c.get(Calendar.DAY_OF_WEEK)) {
case 1:
nReturn = "7";
break;
case 2:
nReturn = "1";
break;
case 3:
nReturn = "2";
break;
case 4:
nReturn = "3";
break;
case 5:
nReturn = "4";
break;
case 6:
nReturn = "5";
break;
case 7:
nReturn = "6";
break;
default:
nReturn = null;
break;
}
list.add(String.valueOf(String.valueOf(week)));
list.add(nReturn);
System.out.println(nReturn);
return list;
}
public static String getWeekOfDate(Date dt) {
String[] weekDays = {"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"};
Calendar cal = Calendar.getInstance();
cal.setTime(dt);
int w = cal.get(Calendar.DAY_OF_WEEK) - 1;
if (w < 0)
w = 0;
return weekDays[w];
}
这两个方法都可以用来实现在一个固定时间段之后去执行JavaScript。不过两者各有各的应用场景。
方 法
实际上,setTimeout和setInterval的语法相同。它们都有两个参数,一个是将要执行的代码字符串,还有一个是以毫秒为单位的时间间隔,当过了那个时间段之后就将执行那段代码。
不过这两个函数还是有区别的,setInterval在执行完一次代码之后,经过了那个固定的时间间隔,它还会自动重复执行代码,而setTimeout只执行一次那段代码。
虽然表面上看来setTimeout只能应用在on-off方式的动作上,不过可以通过创建一个函数循环重复调用setTimeout,以实现重复的操作:
showTime();
function showTime()
{
var today = new Date();
alert("The time is: " + today.toString());
setTimeout("showTime()", 5000);
}
一旦调用了这个函数,那么就会每隔5秒钟就显示一次时间。如果使用setInterval,则相应的代码如下所示: setInterval("showTime()", 5000);
function showTime()
{
var today = new Date();
alert("The time is: " + today.toString());
}
这两种方法可能看起来非常像,而且显示的结果也会很相似,不过两者的最大区别就是,setTimeout方法不会每隔5秒钟就执行一次showTime函数,它是在每次调用setTimeout后过5秒钟再去执行showTime函数。这意味着如果showTime函数的主体部分需要2秒钟执行完,那么整个函数则要每7秒钟才执行一次。而setInterval却没有被自己所调用的函数所束缚,它只是简单地每隔一定时间就重复执行一次那个函数。
如果要求在每隔一个固定的时间间隔后就精确地执行某动作,那么最好使用setInterval,而如果不想由于连续调用产生互相干扰的问题,尤其是每次函数的调用需要繁重的计算以及很长的处理时间,那么最好使用setTimeout。
两个计时函数中的第一个参数是一段代码的字符串,其实该参数也可以是一个函数指针,不过Mac下的IE 5对此不支持。
如果用函数指针作为setTimeout和setInterval函数的第二个参数,那么它们就可以去执行一个在别处定义的函数了:
setTimeout(showTime, 500);
function showTime()
{
var today = new Date();
alert("The time is: " + today.toString());
}
另外,匿名函数还可以声明为内联函数:
setTimeout(function(){var today = new Date();
alert("The time is: " + today.toString());}, 500);
如果对计时函数不加以处理,那么setInterval将会持续执行相同的代码,一直到浏览器窗口关闭,或者用户转到了另外一个页面为止。不过还是有办法可以终止setTimeout和setInterval函数的执行。
当setInterval调用执行完毕时,它将返回一个timer ID,将来便可以利用该值对计时器进行访问,如果将该ID传递给clearInterval,便可以终止那段被调用的过程代码的执行了,具体实现如下:
var intervalProcess = setInterval("alert('GOAL!')", 3000);
var stopGoalLink = document.getElementById("stopGoalLink");
attachEventListener(stopGoalLink, "click", stopGoal, false);
function stopGoal()
{
clearInterval(intervalProcess);
}
只要点击了stopGoalLink,不管是什么时候点击,intervalProcess都会被取消掉,以后都不会再继续反复执行intervalProcess。如果在超时时间段内就取消setTimeout,那么这种终止效果也可以在setTimeout身上实现,具体实现如下: var timeoutProcess = setTimeout("alert('GOAL!')", 3000);
var stopGoalLink = document.getElementById("stopGoalLink");
attachEventListener(stopGoalLink, "click", stopGoal, false);
function stopGoal()
{
clearTimeout(timeoutProcess);
}
<html >
<head>
<style type="text/css">
*{ margin:0; padding:0;}
body {font-size:12px;text-align:center;}
a { color:#04D; text-decoration:none;}
a:hover { color:#F50; text-decoration:underline;}
.SubCategoryBox {width:600px; margin:0 auto; text-align:center;margin-top:40px;}
.SubCategoryBox ul { list-style:none;}
.SubCategoryBox ul li { display:block; float:left; width:200px; line-height:20px;}
.showmore { clear:both; text-align:center;padding-top:10px;}
.showmore a { display:block; width:120px; margin:0 auto; line-height:24px; border:1px solid #AAA;}
.showmore a span { padding-left:15px; background:url(img/down.gif) no-repeat 0 0;}
.promoted a { color:#F50;}
</style>
<!-- 引入jQuery -->
<script src="../../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){ // 等待DOM加载完毕.
var $category = $('ul li:gt(5):not(:last)'); // 获得索引值大于5的品牌集合对象(除最后一条)
$category.hide(); // 隐藏上面获取到的jQuery对象。
var $toggleBtn = $('div.showmore > a'); // 获取“显示全部品牌”按钮
$toggleBtn.click(function(){
if($category.is(":visible")){
$category.hide(); // 隐藏$category
$('.showmore a span')
.css("background","url(img/down.gif) no-repeat 0 0")
.text("显示全部品牌"); //改变背景图片和文本
$('ul li').removeClass("promoted"); // 去掉高亮样式
}else{
$category.show(); // 显示$category
$('.showmore a span')
.css("background","url(img/up.gif) no-repeat 0 0")
.text("精简显示品牌"); //改变背景图片和文本
$('ul li').filter(":contains('佳能'),:contains('尼康'),:contains('奥林巴斯')")
.addClass("promoted"); //添加高亮样式
}
return false; //超链接不跳转
})
})
</script>
</head>
<body>
<div class="SubCategoryBox">
<ul>
<li ><a href="#">佳能</a><i>(30440) </i></li>
<li ><a href="#">索尼</a><i>(27220) </i></li>
<li ><a href="#">三星</a><i>(20808) </i></li>
<li ><a href="#">尼康</a><i>(17821) </i></li>
<li ><a href="#">松下</a><i>(12289) </i></li>
<li ><a href="#">卡西欧</a><i>(8242) </i></li>
<li ><a href="#">富士</a><i>(14894) </i></li>
<li ><a href="#">柯达</a><i>(9520) </i></li>
<li ><a href="#">宾得</a><i>(2195) </i></li>
<li ><a href="#">理光</a><i>(4114) </i></li>
<li ><a href="#">奥林巴斯</a><i>(12205) </i></li>
<li ><a href="#">明基</a><i>(1466) </i></li>
<li ><a href="#">爱国者</a><i>(3091) </i></li>
<li ><a href="#">其它品牌相机</a><i>(7275) </i></li>
</ul>
<div class="showmore">
<a href="more.html"><span>显示全部品牌</span></a>
</div>
</div>
</body>
</html>
javascript点击触发事件
<html>
<head>
<title></title>
<script type="text/javascript">
function demo(){
alert('JavaScript demo.');
}
</script>
</head>
<body>
<p onclick="demo();">点击我.</p>
</body>
</html>
jquery点击触发事件
<html>
<head>
<title></title>
<!-- 引入jQuery -->
<script src="../../scripts/jquery-1.3.1.js" type="text/javascript"></script>
</head>
<body>
<p class="demo">jQuery Demo</p>
<script type="text/javascript">
$(".demo").click(function(){ // 给class为demo 的元素添加行为
alert("jQuery demo!");
})
</script>
</body>
</html>
javascript获得元素改变css
<html >
<head>
</head>
<body>
<div id="tt">test</div>
<script type="text/javascript">
document.getElementById("tt").style.color="red";
</script>
</body>
</html>
jquery得到元素改变css
<html >
<head>
<!-- 引入jQuery -->
<script src="../../scripts/jquery-1.3.1.js" type="text/javascript"></script>
</head>
<body>
<div id="tt">test</div>
<script type="text/javascript">
$('#tt').css("color","yellow");
</script>
</body>
</html>
javascript多选的得到值
<html >
<head>
<script type="text/javascript">
window.onload = function(){//页面所有元素加载完毕
var btn = document.getElementById("btn"); //获取id为btn的元素(button)
btn.onclick = function(){ //给元素添加onclick事件
var arrays = new Array(); //创建一个数组对象
var items = document.getElementsByName("check"); //获取name为check的一组元素(checkbox)
for(i=0; i < items.length; i++){ //循环这组数据
if(items[i].checked){ //判断是否选中
arrays.push(items[i].value); //把符合条件的 添加到数组中. push()是javascript数组中的方法.
}
}
alert( "选中的个数为:"+arrays.length );
}
}
</script>
</head>
<body>
<form method="post" action="#">
<input type="checkbox" value="1" name="check" checked="checked"/>
<input type="checkbox" value="2" name="check" />
<input type="checkbox" value="3" name="check" checked="checked"/>
<input type="button" value="你选中的个数" id="btn"/>
</form>
</body>
</html>
jquery隔行换色
<html >
<head>
<!-- 引入jQuery -->
<script src="../../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script language="javascript" >
$(function(){// dom元素加载完毕
$('#tb tbody tr:even').css("backgroundColor","#888");//偶数行
$('#tb tbody tr:odd').css("backgroundColor","red");//奇数行
//获取id为tb的元素,然后寻找他下面的tbody标签,再寻找tbody下索引值是偶数的tr元素,
//改变它的背景色.
})
</script>
</head>
<body>
<table id="tb">
<tbody>
<tr><td>第一行</td><td>第一行</td></tr>
<tr><td>第二行</td><td>第二行</td></tr>
<tr><td>第三行</td><td>第三行</td></tr>
<tr><td>第四行</td><td>第四行</td></tr>
<tr><td>第五行</td><td>第五行</td></tr>
<tr><td>第六行</td><td>第六行</td></tr>
</tbody>
</table>
</body>
</html>
javascript隔行换色
<html >
<head>
<script type="text/javascript">
window.onload = function(){ //页面所有元素加载完毕
var item = document.getElementById("tb"); //获取id为tb的元素(table)
var tbody = item.getElementsByTagName("tbody")[0]; //获取表格的第一个tbody元素
var trs = tbody.getElementsByTagName("tr"); //获取tbody元素下的所有tr元素
for(var i=0;i < trs.length;i++){//循环tr元素
if(i%2==0){ //取模. (取余数.比如 0%2=0 , 1%2=1 , 2%2=0 , 3%2=1)
trs[i].style.backgroundColor = "#888"; // 改变 符合条件的tr元素 的背景色.
}else {
trs[i].style.backgroundColor = "red";
}
}
}
</script>
</head>
<body>
<table id="tb">
<tbody>
<tr><td>第一行</td><td>第一行</td></tr>
<tr><td>第二行</td><td>第二行</td></tr>
<tr><td>第三行</td><td>第三行</td></tr>
<tr><td>第四行</td><td>第四行</td></tr>
<tr><td>第五行</td><td>第五行</td></tr>
<tr><td>第六行</td><td>第六行</td></tr>
</tbody>
</table>
</body>
</html>
jquery得到checkbox值
<html>
<head>
<!-- 引入jQuery -->
<script src="../../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script language="javascript" >
$(function(){// dom元素加载完毕
$('#btn').click(function(){ //获取id为btn的元素,给它添加onclick事件
var items = $("input[name='check']:checked");
//获取name为check的一组元素,然后选取它们中选中(checked)的。
// alert( "选中的个数为:"+items.length )
items.each(function(){
alert($(this).val());
});
})
})
</script>
</head>
<body>
<input type="checkbox" value="1" name="check" checked/>
<input type="checkbox" value="2" name="check" />
<input type="checkbox" value="3" name="check" checked/>
<input type="button" value="测试选中的个数" id="btn"/>
</body>
</html>
$('ul li:gt(5):not(:last)') :
选取ul元素下的li元素的索引值大于5的集合元素后,去掉集合元素中的最后一个。
索引值从0开始。
DOM方式
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>1-6-2</title>
<!-- 引入 jQuery -->
<script src="../../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script type="text/javascript">
//等待dom元素加载完毕.
$(document).ready(function(){
var $cr = $("#cr"); //jQuery对象
var cr = $cr.get(0); //DOM对象,获取 $cr[0]
$cr.click(function(){
if(cr.checked){ //DOM方式判断
alert("感谢你的支持!你可以继续操作!");
}
})
});
</script>
</head>
<body>
<input type="checkbox" id="cr"/> <label for="cr">我已经阅读了上面制度.</label>
</body>
</html>
jQuery方式
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>1-6-1</title>
<!-- 引入 jQuery -->
<script src="../../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script type="text/javascript">
//等待dom元素加载完毕.
$(document).ready(function(){
var $cr = $("#cr"); //jQuery对象
$cr.click(function(){
if($cr.is(":checked")){ //jQuery方式判断
alert("感谢你的支持!你可以继续操作!");
}
})
});
</script>
</head>
<body>
<input type="checkbox" id="cr"/><label for="cr">我已经阅读了上面制度.</label>
</body>
</html>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>1-5-1</title>
<style type="text/css">
#menu {
width:300px;
}
.has_children{
background : #555;
color :#fff;
cursor:pointer;
}
.highlight{
color : #fff;
background : green;
}
div{
padding:0;
}
div a{
background : #888;
display : none;
float:left;
width:300px;
}
</style>
<!-- 引入 jQuery -->
<script src="../../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script type="text/javascript">
//等待dom元素加载完毕.
$(document).ready(function(){
$(".has_children").click(function(){
$(this).addClass("highlight") //为当前元素增加highlight类
.children("a").show().end() //将子节点的a元素显示出来并重新定位到上次操作的元素
.siblings().removeClass("highlight") //获取元素的兄弟元素,并去掉他们的highlight类
.children("a").hide(); //将兄弟元素下的a元素隐藏
});
});
</script>
</head>
<body>
<div id="menu">
<div class="has_children">
<span>第1章-认识jQuery</span>
<a>1.1-JavaScript和JavaScript库</a>
<a>1.2-加入jQuery</a>
<a>1.3-编写简单jQuery代码</a>
<a>1.4-jQuery对象和DOM对象</a>
<a>1.5-解决jQuery和其它库的冲突</a>
<a>1.6-jQuery开发工具和插件</a>
<a>1.7-小结</a>
</div>
<div class="has_children">
<span>第2章-jQuery选择器</span>
<a>2.1-jQuery选择器是什么</a>
<a>2.2-jQuery选择器的优势</a>
<a>2.3-jQuery选择器</a>
<a>2.4-应用jQuery改写示例</a>
<a>2.5-选择器中的一些注意事项</a>
<a>2.6-案例研究——类似淘宝网品牌列表的效果</a>
<a>2.7-还有其它选择器么?</a>
<a>2.8-小结</a>
</div>
<div class="has_children">
<span>第3章-jQuery中的DOM操作</span>
<a>3.1-DOM操作的分类</a>
<a>3.2-jQuery中的DOM操作</a>
<a>3.3-案例研究——某网站超链接和图片提示效果</a>
<a>3.4-小结</a>
</div>
</div>
</body>
</html>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>1-4</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<!-- 引入 jQuery -->
<script src="../scripts/jquery-1.3.1.js" type="text/javascript"></script>
<script type="text/javascript">
//等待dom元素加载完毕.
$(document).ready(function(){
var domObj = document.getElementsByTagName("h3")[0]; // Dom对象
var $jQueryObj = $(domObj); //jQuery对象
alert("DOM对象:"+domObj.innerHTML);
alert("jQuery对象:"+$jQueryObj.html());
});
</script>
</head>
<body>
<h3>例子</h3>
</body>
</html>
摘要: //定义一个对象 var obj = new Object(); //动态创建属性name obj.name = "an object"; //动态创建属性sayHi obj.sayHi = function(){ return "Hi";...
阅读全文
HaspMap的遍历。 Map<String, String[]> paraMap = new HashMap<String, String[]>(); for( Entry<String, String[]> entry : paraMap.entrySet() )
{ String appFieldDefId = entry.getKey(); String[] values = entry.getValue(); }
利用散列值取出相应的Entry做比较得到结果,取得entry的值之后直接取key和 value。
奇偶判断 不要使用 i % 2 == 1 来判断是否是奇数,因为i为负奇数时不成立,请使用 i % 2 != 0 来判断是否是奇数,或使用 高效式 (i & 1) != 0来判断。
六、避免不需要的instanceof操作 如果左边的对象的静态类型等于右边的,instanceof表达式返回永远为true。 例子: public class uiso { public uiso () {} } class dog extends uiso { void method (dog dog, uiso u) { dog d = dog;if (d instanceof uiso) // always true. system.out.println("dog is a uiso"); uiso uiso = u; if (uiso instanceof object) // always true. system.out.println("uiso is an object"); } } 更正: 删掉不需要的instanceof操作。 class dog extends uiso { void method () { dog d; system.out.println ("dog is an uiso"); system.out.println ("uiso is an uiso"); } }
七、避免不需要的造型操作 所有的类都是直接或者间接继承自object。同样,所有的子类也都隐含的“等于”其父类。那么,由子类造型至父类的操作就是不必要的了。 例子: class unc { string _id = "unc"; } class dog extends unc { void method () { dog dog = new dog (); unc animal = (unc)dog; // not necessary. object o = (object)dog; // not necessary. } } 更正: class dog extends unc { void method () { dog dog = new dog(); unc animal = dog; object o = dog; } }
八、如果只是查找单个字符的话,用charat()代替startswith()
用一个字符作为参数调用startswith()也会工作的很好,但从性能角度上来看,调用用string api无疑是错误的! 例子: public class pcts { private void method(string s) { if (s.startswith("a")) { // violation // ... } } } 更正 将'startswith()' 替换成'charat()'. public class pcts { private void method(string s) { if ('a' == s.charat(0)) { // ... } } }
九、使用移位操作来代替'a / b'操作 "/"是一个很“昂贵”的操作,使用移位操作将会更快更有效。 例子: public class sdiv { public static final int num = 16; public void calculate(int a) { int div = a / 4; // should be replaced with "a >> 2". int div2 = a / 8; // should be replaced with "a >> 3". int temp = a / 3; } } 更正: public class sdiv { public static final int num = 16; public void calculate(int a) { int div = a >> 2; int div2 = a >> 3; int temp = a / 3; // 不能转换成位移操作 } }
十、使用移位操作代替'a * b'
同上。 [i]但我个人认为,除非是在一个非常大的循环内,性能非常重要,而且你很清楚你自己在做什么,方可使用这种方法。否则提高性能所带来的程序晚读性的降低将是不合算的。 例子: public class smul { public void calculate(int a) { int mul = a * 4; // should be replaced with "a << 2". int mul2 = 8 * a; // should be replaced with "a << 3". int temp = a * 3; } } 更正: package opt; public class smul { public void calculate(int a) { int mul = a << 2; int mul2 = a << 3; int temp = a * 3; // 不能转换 } }
十一、在字符串相加的时候,使用 ' ' 代替 " ",如果该字符串只有一个字符的话 例子: public class str { public void method(string s) { string string = s + "d" // violation. string = "abc" + "d" // violation. } } 更正: 将一个字符的字符串替换成' ' public class str { public void method(string s) { string string = s + 'd' string = "abc" + 'd' } }
十二、将try/catch块移出循环 把try/catch块放入循环体内,会极大的影响性能,如果编译jit被关闭或者你所使用的是一个不带jit的jvm,性能会将下降21%之多! 例子: import java.io.fileinputstream; public class try { void method (fileinputstream fis) { for (int i = 0; i < size; i++) { try { // violation _sum += fis.read(); } catch (exception e) {} } } private int _sum; } 更正: 将try/catch块移出循环 void method (fileinputstream fis) { try { for (int i = 0; i < size; i++) {
_sum += fis.read(); } } catch (exception e) {} }
十三、对于boolean值,避免不必要的等式判断 将一个boolean值与一个true比较是一个恒等操作(直接返回该boolean变量的值). 移走对于boolean的不必要操作至少会带来2个好处: 1)代码执行的更快 (生成的字节码少了5个字节); 2)代码也会更加干净 。 例子: public class ueq { boolean method (string string) { return string.endswith ("a") == true; // violation } } 更正: class ueq_fixed { boolean method (string string) { return string.endswith ("a"); } }
十四、对于常量字符串,用'string' 代替 'stringbuffer' 常量字符串并不需要动态改变长度。 例子: public class usc { string method () { stringbuffer s = new stringbuffer ("hello"); string t = s + "world!"; return t; } } 更正: 把stringbuffer换成string,如果确定这个string不会再变的话,这将会减少运行开销提高性能。
十五、使用条件操作符替代"if (cond) return; else return;" 结构 条件操作符更加的简捷 例子: public class if { public int method(boolean isdone) { if (isdone) { return 0; } else { return 10; } } } 更正: public class if { public int method(boolean isdone) { return (isdone ? 0 : 10); } }
十六、不要在循环体中实例化变量 在循环体中实例化临时变量将会增加内存消耗 例子: import java.util.vector; public class loop { void method (vector v) { for (int i=0;i < v.size();i++) { object o = new object(); o = v.elementat(i); } } } 更正: 在循环体外定义变量,并反复使用 import java.util.vector; public class loop { void method (vector v) { object o; for (int i=0;i<v.size();i++) { o = v.elementat(i); } } }
一、避免在循环条件中使用复杂表达式 在不做编译优化的情况下,在循环中,循环条件会被反复计算,如果不使用复杂表达式,而使循环条件值不变的话,程序将会运行的更快。 例子: import java.util.vector; class cel { void method (vector vector) { for (int i = 0; i < vector.size (); i++) // violation ; // } } 更正: class cel_fixed { void method (vector vector) { int size = vector.size () for (int i = 0; i < size; i++) ; // } } 二、为'vectors' 和 'hashtables'定义初始大小 jvm为vector扩充大小的时候需要重新创建一个更大的数组,将原原先数组中的内容复制过来,最后,原先的数组再被回收。可见vector容量的扩大是一个颇费时间的事。 通常,默认的10个元素大小是不够的。你最好能准确的估计你所需要的最佳大小。 例子: import java.util.vector;
public class dic { public void addobjects (object[] o) { // if length > 10, vector needs to expand for (int i = 0; i< o.length;i++) { v.add(o); // capacity before it can add more elements. } } public vector v = new vector(); // no initialcapacity. } 更正: 自己设定初始大小。 public vector v = new vector(20); public hashtable hash = new hashtable(10);
三、在finally块中关闭stream 程序中使用到的资源应当被释放,以避免资源泄漏。这最好在finally块中去做。不管程序执行的结果如何,finally块总是会执行的,以确保资源的正确关闭。 例子: import java.io.*; public class cs { public static void main (string args[]) { cs cs = new cs (); cs.method (); } public void method () { try { fileinputstream fis = new fileinputstream ("cs.java"); int count = 0; while (fis.read () != -1) count++; system.out.println (count); fis.close (); } catch (filenotfoundexception e1) { } catch (ioexception e2) { } } } 更正: 在最后一个catch后添加一个finally块
四、使用'system.arraycopy ()'代替通过来循环复制数组 'system.arraycopy ()' 要比通过循环来复制数组快的多。 例子: public class irb { void method () { int[] array1 = new int [100]; for (int i = 0; i < array1.length; i++) { array1 [i] = i; } int[] array2 = new int [100]; for (int i = 0; i < array2.length; i++) { array2 [i] = array1 [i]; // violation } } } 更正: public class irb{ void method () { int[] array1 = new int [100]; for (int i = 0; i < array1.length; i++) { array1 [i] = i; } int[] array2 = new int [100]; system.arraycopy(array1, 0, array2, 0, 100); } }
五、让访问实例内变量的getter/setter方法变成”final” 简单的getter/setter方法应该被置成final,这会告诉编译器,这个方法不会被重载,所以,可以变成”inlined” 例子: class maf { public void setsize (int size) { _size = size; } private int _size; } 更正: class daf_fixed { final public void setsize (int size) { _size = size; } private int _size; }
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css" media="all">
label{
cursor:pointer;
font-size:12px;
margin:0px 2px 0px 0px;
color:#2B86BD;
}
.d0{
margin-bottom:30px;
}
.d0 input{
cursor:pointer;
margin:0px;
padding:0px 2px;
}
</style>
<script language="javascript" type="text/javascript">
var dr=document.getElementsByTagName("div"),i,t="";
function submit1(num,type){
t="";
var dri=dr[num].getElementsByTagName("input");
for(i=0;i<dri.length;i++){
if(dri[i].checked){
if(type==0){
alert(dri[i].value);
break;
}else{
t=t+dri[i].value+";";
}
}
}
if(type==1) alert(t);
}
//ChangeSelect
submit1.allselect=function(){
var drc=dr[1].getElementsByTagName("input");
for(i=0;i<drc.length;i++){
drc[i].checked=true;
}
}
//allNot
submit1.allNot=function(){
var drc=dr[1].getElementsByTagName("input");
for(i=0;i<drc.length;i++){
drc[i].checked=false;
}
}
//reverse
submit1.reverseSelect=function(){
var drc=dr[1].getElementsByTagName("input");
for(i=0;i<drc.length;i++){
if(drc[i].checked){
drc[i].checked=false;
}else{
drc[i].checked=true;
}
}
}
</script>
<title>js获取单选框、复选框的值及操作</title>
</head>
<body>
<div class="d0">
<input type="radio" name="day" id="r0" value="前天"/><label for="r0">前天</label>
<input type="radio" name="day" id="r1" value="昨天"/><label for="r1">昨天</label>
<input type="radio" name="day" id="r2" checked="checked" value="今天"/><label for="r2">今天</label>
<input type="radio" name="day" id="r3" value="明天"/><label for="r3">明天</label>
<input type="radio" name="day" id="r4" value="后天"/><label for="r4">后天</label>
<button type="button" onclick="submit1(0,0)" >提交</button>
</div>
<div>
<input type="checkbox" value="前年" onclick="alert(this.value);"/><label>前年</label>
<input type="checkbox" value="去年" onclick="submit1(1,1);"/><label>去年</label>
<input type="checkbox" value="今年" /><label>今年</label>
<input type="checkbox" value="明年"/><label>明年</label>
<input type="checkbox" value="后年"/><label>后年</label>
<button type="button" onclick="submit1(1,1)" >提交</button>
<button type="button" onclick="submit1.allselect()" >全选</button>
<button type="button" onclick="submit1.reverseSelect()" >反选</button>
<button type="button" onclick="submit1.allNot()" >全不选</button>
</div>
</body>
</html>
var stroeName = new Ext.data.JsonStore({
autoLoad : true,
url : "BookAction_getName.action",
root : "options",
fields : [
'name','id'
]
});
var state = new Ext.form.ComboBox({
name : 'name',
fieldLabel : '图书名',
allowBlank : false,
blankText : '请选择',
emptyText : '请选择',
editable : false,
triggerAction : 'all',
store : stroeName,
//加载本地数据框
mode : 'local',
displayField : 'name',
valueField : 'id',
hiddenName :'id',
//hiddenName :'id',
width : 125
});
1.在采集温湿度数据时,现在config下建立温湿度的文件夹(view),
2.在此文件夹下新建立NumericWritable的wen节点,在view中建立kitPx中的Bargraph柱状图,编辑对应wen节点中out中的value,
3.在控制灯的开关时在kitPx中选择ActionButton,为每个灯选择2个ActionButton,一个开,一个关,编辑开的开关选择此灯节点中的emergencyActive,编辑关的开关选择此灯节点中的emergencyInactive,
4.在Palette中找iopt,找host,,在config下建立iopt文件夹,Local Port设置6800,Dest Port设置1025
1.在tools中选择new station,新建一个station
2.点击Platform启动新建的station
3.在File中选择open station(fox)点击
4.选择station中的Config右键新建文件夹(如yang)
5.在此文件夹下右键新疆Wire Sheet
6.在Wire Sheet下右键选择new 一个numericWritable
7.在这个numericWritable右键action中set数值
8.重复6.7再次建立一个标准值的numericWritable
9.在Wire Sheet下右键选择new 一个BooleanWritable
10.在这个BooleanWritable右键action中setboolean值
11.在Window中的Side Bars中点击Palette
12.在Palette中找到kitControl中的Logic中的GreaterThan拖入到Wire Sheet中
13.让两个的numericWritable的Out分别指向GreaterThan的A和B(A>B是true)
14.再让GreaterThan的Out指向BooleanWritable其中一个值
15.在yang文件夹右键点击Views中的New View
16.在kitPx中把AnalogMeter拖入New View,再双击New View选择ord
在ord的弹出框中的下箭头选择Component Chooser,,选择yang文件夹中的一个值(不是标准值)
17.在KitPxHvac中的boolean中的bulb,拖入New View,再双击New View选择ord
在ord的弹出框中的下箭头选择Component Chooser,,选择yang文件夹中的boolean对象。
当用户访问系统时,所有请求先进过在web.xml中配置的com.jfinal.core.JFinalFilter这个核心类,
先执行这个类的的init方法,实例化jfinalConfig对象,这个对象是需要开发者自己定义一个类继承
JFinalConfig类,实现几个抽象方法,其中public void configConstant(Constants me)方法是配置数据库的信息,
开发模式,视图的类型等,public void configRoute(Routes me)方法是配置访问路径的路由信息,
public void configPlugin(Plugins me) 方法是配置数据库连接,其他一些插件,对象模型, public void configInterceptor(Interceptors me)方法是配置全局拦截器,public void configHandler(Handlers me)
是配置处理器,此方法会得到访问的url,进行处理。此类需要在web.xml中配置,如下:
<filter>
<filter-name>jfinal</filter-name>
<filter-class>com.jfinal.core.JFinalFilter</filter-class>
<init-param>
<param-name>configClass</param-name>
<param-value>com.demo.config.DemoConfig</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>jfinal</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
在JFinalFilter类中当执行完init方法后,会执行jfinal类的init方法,此方法是先定义得到工程的路径,再初始化开发者刚刚写的
继承JFinalConfig类的类,读入配置信息。当init方法执行完后,执行doFilter方法,得到用户访问的url,分到不同的handler中进行处理
摘要: import java.util.*;002import java.text.*;003import java.util.Calendar;004public class VeDate {005 /**006 * 获取现在时间007 * 008 * <a href="http://my.oschina.net/u/5...
阅读全文
摘要: 1. 字符串有整型的相互转换 1 2 String a = String.valueOf(2); //integer to numeric string 3 int i = Integer.parseInt(a); //numeric string to an int ...
阅读全文
摘要: 1.svn环境搭建在应用myEclips 8.5做项目时,svn会成为团队项目的一个非常好的工具,苦苦在网上寻求了一下午,终于整合好了这个环境,在这里简单介绍下,希望能为刚开始用svn的朋友一点点帮助。 svn环境需要(1)服务器端(2)客户端(3)应用在myeclipse中的svn插件 第一步,安装svn服务器端。我用的是VisualSVN-Server-2.1.3这...
阅读全文
1. 打开MyEclipse,然后 Window-------->Preferences;
2.选择Java-------->展开-------->Editor-------->选择ContentAssist;
3.选择ContentAssist-------->然后看到右边-------->右边的Auto-Activation下面的Auto Activation triggers for java(指触发代码提示的就是”.”这个符号)这个选项;
4. AutoActivation triggers for java这个选项-------->在”.”后加abcdefghijklmnopqrstuvwxyz
字母,方便后面的查找修改-------->然后apply-------->点击OK;
摘要: Struts2 Taglib抽象了不同表示技术,现在Struts2主要支持三种表示技术:JSP,FreeMarker和Velocity。但部分的Tag在三种表示技术下都可以使用,但是也有部分只能在某一种情况下使用。 Tab可以分为两类:通用标签和UI标签。 4.1节 通用标签 通用标签用来在页面表示的时候控制代码执行的过程,这些标签也允许从Action或者值堆栈中取得数据。例如地域,JavaBea...
阅读全文
4.1连接池知识简介
众所周知建立数据库连接是一个非常耗时耗资源的行为,因此现代的Web中间件,无论是开源的Tomcat、Jboss还是商业的 websphere、weblogic都提供了数据库连接池功能,可以毫不夸张的说,数据库连接池性能的好坏,不同厂商对连接池有着不同的实现,本文只介 绍拜特公司使用较多的开源web中间件Tomcat中默认的连接池DBCP(DataBase connection pool)的使用。
4.2 Tomcat下配置连接池
下面以tomcat5.5.26为例来介绍如何配置连接池
1:需要的jar
在tomcat的安装目录common\lib下有一个naming-factory-dbcp.jar,这个是tomcat修改后的dbcp连接池实现,同时为了能够正常运行,还需要commons-pool.jar。
2:建立context文件
进入到conf\Catalina\localhost新建一个上下文文件,文件的名称既为将来要访问是输入url上下文名称,例如我们建立一个名为btweb的文件内容如下:
<Context debug="0"docBase="D:\v10_workspace\build\WebRoot" reloadable="false">
<Resource
name="jdbc/btdb1"
type="javax.sql.DataSource"
factory="org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory"
username="v10"
password="v10"
driverClassName="oracle.jdbc.driver.OracleDriver"
url="jdbc:oracle:thin:@127.0.0.1:1521:cahs"
maxActive="5"
maxIdle="3"
maxWait="5000"
removeAbandoned="true"
removeAbandonedTimeout="60"
testOnBorrow="true"
validationQuery="selectcount(*) from bt_user"
logAbandoned="true"
/>
</Context>
4.3参数分步介绍
u 数据库连接相关
username="v10"
password="v10"
driverClassName="oracle.jdbc.driver.OracleDriver"
url="jdbc:oracle:thin:@127.0.0.1:1521:cahs"
u jndi相关
name="jdbc/btdb1"
type="javax.sql.DataSource"
factory="org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory"
factory默认是org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory,tomcat也允许采用其他连接实现,不过默认使用dbcp。
u 连接数控制与连接归还策略
maxActive="5"
maxIdle="3"
minIdle=”2”
maxWait="5000"
u 应对网络不稳定的策略
testOnBorrow="true"
validationQuery="selectcount(*) from bt_user"
u 应对连接泄漏的策略
removeAbandoned="true"
removeAbandonedTimeout="60"
logAbandoned="true"
如下图所示:连接池处于应用程序与数据库之间,一方面应用程序通过它来获取连接,归还连接,另一方面连接又需要从数据里获取连接,归还连接。
步骤1:系统启动
系统启动时,初始化连接池,由于没有任何请求连接池中连接数为0。
maxActive="5"
表示并发情况下最大可从连接池中获取的连接数。如果数据库不是单独,供一个应用使用,通过设置maxActive参数可以避免某个应用无限制的获取 连接对其他应用造成影响,如果一个数据库只是用来支持一个应用那么maxActive理论上可以设置成该数据库可以支撑的最大连接数。maxActive 只是表示通过连接池可以并发的获取的最大连接数。
从图上我们可以看到连接的获取与释放是双向,当应用程序并发请求连接池时,连接池就需要从数据库获取连接,那么但应用程序使用完连接并将连接归还给 连接池时,连接池是否也同时将连接归还给数据库呢?很显然答案是否定的,如果那样的话连接池就变得多此一举,不但不能提高性能,反而会降低性能,那么但应 用成归还连接后,连接池如何处理呢?
maxIdle="3"
如果在并发时达到了maxActive=5,那么连接池就必须从数据库中获取5个连接来供应用程序使用,当应用程序关闭连接后,由于maxIdle=3,因此并不是所有的连接都会归还给数据库,将会有3个连接保持在连接池种中,状态为空闲。
minIdle=”2”
最小默认情况下并不生效,它的含义是当连接池中的连接少有minIdle,系统监控线程将启动补充功能,一般情况下我们并不启动补充线程。
问题:如何设置maxActive和maxIdle?
理论上讲maxActive应该设置成应用的最大并发数,这样一来即便是在最大并发的情况下,应用依然能够从连接池中获取连接,但是困难时的是我们 很难准确估计到最大并发数,设置成最大并发数是一种最优的服务质量保证,事实上,如果某个用户登录提示系统繁忙,那么在他再次登录时,可能系统资源已经充 足,对于拜特资金管理系统我们建议将maxActive设置为系统注册人数的十分之一到二十分之一之间。例如系统的注册人数为1000,那么设置成50-100靠近100的数字,例如85或90。
maxIdle对应的连接,实际上是连接池保持的长连接,这也是连接池发挥优势的部分,理论上讲保持较多的长连接,在应用请求时可以更快的响应,但是过多的连接保持,反而会消耗数据库大量的资源,因此maxIdle也并不是越大越好,同上例我们建议将maxIdle设置成
50-100中靠近50的数字,例如55。这样就能在兼顾最大并发同时,保持较少的数据库连接,而且在绝大多情况,能够为应用程序提供最快的相应速度。
testOnBorrow="true"
validationQuery="selectcount(*) from bt_user"
我们知道数据库连接从本质上架构在tcp/ip连接之上,一般情况下web服务器与数据库服务器都不在同一台物理机器上,而是通过网络进行连接,那 么当建立数据库连接池的机器与数据库服务器自己出现网络异常时,保持在连接池中的连接将失效,不能够在次使用,传统的情况下只能通过重新启动,再次建立连 接,通过设置以上两个参数,但应用程序从连接池中获取连接时,会首先进行活动性检测,当获取的连接是活动的时候才会给应用程序使用,如果连接失效,连接将 释放该连接。validationQuery是一条测试语句,没有实际意义,现实中,一般用一条最为简单的查询语句充当。
removeAbandoned="true"
removeAbandonedTimeout="60"
logAbandoned="true"
有时粗心的程序编写者在从连接池中获取连接使用后忘记了连接的关闭,这样连池的连接就会逐渐达到maxActive直至连接池无法提供服务。现代连接池一般提供一种“智能”的检查,但设置了removeAbandoned="true"时,当连接池连接数到达(getNumIdle() < 2) and (getNumActive() > getMaxActive() - 3)时便会启动连接回收,那种活动时间超过removeAbandonedTimeout="60"的连接将会被回收,同时如果logAbandoned="true"设置为true,程序在回收连接的同时会打印日志。removeAbandoned是连接池的高级功能,理论上这中配置不应该出现在实际的生产环境,因为有时应用程序执行长事务,可能这种情况下,会被连接池误回收,该种配置一般在程序测试阶段,为了定位连接泄漏的具体代码位置,被开启,生产环境中连接的关闭应该靠程序自己保证。
经过一段时间的闭关练习,终于对struts2有所了解.其实struts2并不难, 一看就能明白其中奥妙.我对struts2的验证体系保留怀疑态度,因为它的验证消息使用标签打在页面上,实在太丑,在真实项目中不知道是否有人这么做. 也许是我太菜了,还不知道如何将验证消息显示得更友好,希望各位不吝拍砖指导.
然而,我认为struts2最复杂难学的是它内置的ognl表达式.这个ognl在我开始学struts2时,让我云里雾里,不知如何应对.经过几轮 的翻看书籍,与网上资料查询,还算是让我有所明白一点.在此记录,以便日后温习,同时,如果这篇文章对各位有哪怕一点帮助,那便是我最大的荣幸.
首先,要知道ognl最主要的功能就是取数据,它可以利用一段简短的表达式取出各种各样丰富的数据.其次,它还附带了一些便捷的功能,如:方法调用、 静态方法和属性调用、数值运算……我们最关心的是如何取数据,因此,接下来我将重点介绍如何取数据,至于附带功能将不做介绍。
知道了ognl最主要的功能是取数据后,那么数据从哪里取呢!ognl会从两个地方取:一个是Action的实例属性;另一个是 ValueStack(中文名叫值栈)。ognl会先从前者里面取,如果没取到再到ValueStack里取。Action的实例属性好理解,但这个 ValueStack从字面上看,着实不好理解,以致于我将struts2的源码引进eclipse里,单步调试才算有所启发。可以将 ValueStack初步理解为一个map,在这个map里存储了request、session、application、response、 action实例、parameters数组……还有很多你不知道的对象。有了这个map,还愁数据取不到吗。
注意:将ValueStack初步理解为一个map,只适于初学struts2的人,其实它内部并没这么简单。由于水平、时间有限,我并不能掌握其内 部精髓,加上表达能力不佳,怕表达不对误导大家,所以我们姑且理解ValueStack为一个map吧。如果想更深的了解的ValueStack,请查看 struts2的源码。 接下来,便是取数据。取action实例的属性数据与取ValueStack中的数据不一样,先说取action实例的属性数据吧。
action实例的属性数据可以直接在struts2的标签中通过属性名取到。如:<s:property value="name"/>、<s:property value="user.password"/>
注意:不要加#号。
再是取ValueStack中的数据。
struts2提供三种方式通过ognl表达式来取ValueStack中的数据:#、%{}、${}
#和%{}需要放到struts2提供的标签里才生效。如:<s:property value="#name"/>、<s:property value="%{'hello struts2'}"/>
一、最常用的方式是:#
1.#能取request、session、application里的attribute,但需要加前缀。如:<s:property value="#session.name2"/>、<s:property value="#application.name3"/>。如果是取request范围的attribute,那么不需要加request前缀, 加上反而取不到数据,ognl默认从request里取,如果没有取到并不会到session或application里取。 如:<s:property value="#name"/>
2.#能取request里的请求参数,但必须加parameters前缀,且取到的是一个数组,所以如果你要得到参数的第一项值,那么还要加下标。 如:<s:property value="#parameters.name[0]"/>。这相当于调用 request.getParameterValues("name")[0];
3.#加attr前缀能按request > session > application顺序获取attribute,这样当在request中取不到时,会自动向session里取,如果session里也取不到,会 再向application里取。如果取到则返回,不再向上游历。如:<s:property value="#attr.name"/>
4.#能构造Map,如:<s:set name="foobar" value="#{'foo1':'bar1', 'foo2':'bar2'}" /><s:property value="#foobar['foo1']" />
5.#能用于过滤和投影(projecting)集合,如:books.{?#this.price<100}
以上第4、5项功能,我没有做过多介绍,因为目前为止这两项功能我使用并不多。
二、%{}的用途是在标签的属性为字符串类型时,计算OGNL表达式的值。这个功能目前还没有深刻体会,故不介绍。
三、${}有两个主要的用途。
1.用于在国际化资源文件中,引用OGNL表达式。
2.在Struts 2配置文件中,引用OGNL表达式。如 :
<action name="AddPhoto" class="addPhoto">
<interceptor-ref name="fileUploadStack" />
<result type="redirect">ListPhotos.action?albumId=${albumId}</result>
</action>
以上,其实主要介绍了#的使用,大部分情况下我们只与它打交道,另外两种方式需要在以后的项目中多多使用才能有所体会。
其实,我是jstl+el的忠实粉丝,在任何项目中,只要能用上jstl标签的,我决不用其它标签。因为它是官方标准,还有它简单且已熟练,我已在众多项目中实战演练过,有了它们,我不想在使用其它标签。
说到了这里,我还是有必要再多说两句,是不是使用了struts2,就不能再用el来取数据了呢?答案是否定的,完全可以使用el来取数据。 struts2会将ValueStack里的session、application里的attribute完全复制到HttpSession、 ServletContext里,这样el表达式照样能取到这两个Scope里的数据。然而,struts2并没有将ValueStack里的 request里的attribute复制到HttpServletRequest,这是不是意味着el表达式就不能取request里的数据了呢?还是 可以,不只可以取request里的数据,还可以取action实例的属性值。神奇吧!奥秘就在struts2对request做了封装,这个封装类是 org.apache.struts2.dispatcher.StrutsRequestWrapper,它重写了getAttribute()方法, 该方法先从真实的request类里取attribute,如果取到则返回,如果没有取到则从ValueStack里取,现在明白了吧!
一 :Oracle
驱动:oracle.jdbc.driver.OracleDriver
URL:jdbc:oracle:thin:@<machine_name><:port>:dbname
注:machine_name:数据库所在的机器的名称,如果是本机则是127.0.0.1或者是localhost,如果是远程连接,则是远程的IP地址;
port:端口号,默认是1521
二:SQL Server
驱动:com.microsoft.jdbc.sqlserver.SQLServerDriver
URL:jdbc:microsoft:sqlserver://<machine_name><:port>;DatabaseName=<dbname>
注:machine_name:数据库所在的机器的名称,如果是本机则是127.0.0.1或者是localhost,如果是远程连接,则是远程的IP地址;
port:端口号,默认是1433
三:MySQL
驱动:org.gjt.mm.mysql.Driver
URL:jdbc:mysql://<machine_name><:port>/dbname
注:machine_name:数据库所在的机器的名称,如果是本机则是127.0.0.1或者是localhost,如果是远程连接,则是远程的IP地址;
port:端口号,默认3306
四:pointbase
驱动:com.pointbase.jdbc.jdbcUniversalDriver
URL:jdbc:pointbase:server://<machine_name><:port>/dbname
注:machine_name:数据库所在的机器的名称,如果是本机则是127.0.0.1或者是localhost,如果是远程连接,则是远程的IP地址;
port:端口号,默认是9092
五:DB2
驱动:com.ibm.db2.jdbc.app.DB2Driver
URL:jdbc:db2://<machine_name><:port>/dbname
注:machine_name:数据库所在的机器的名称,如果是本机则是127.0.0.1或者是localhost,如果是远程连接,则是远程的IP地址;
port:端口号,默认是5000
一、function概述
javascript中的函数不同于其他的语言,每个函数都是作为一个对象被维护和运行的。通过函数对象的性质,可以很方便的将一个函数赋值给一个变量或者将函数作为参数传递。
函数对象与其他用户所定义的对象有着本质的区别,这一类对象被称之为内部对象。内置对象的构造器是由JavaScript本身所定义的。
二、function对象的创建
在JavaScript中,函数对象对应的类型是Function,可以通过new Function()来创建一个函数对象,也可以通过function关键字来创建一个对象。
//使用new Function()方式创建
var myFunction=new Function("a","b","return a+b");
//使用function关键字创建
function myFunction(a,b) {
return a + b;
}
用关键字创建对象的时候,在解释器内部,就会自动构造一个Function对象,将函数作为一个内部的对象来存储和运行。从这里也可以看到,一个函数对象 名称(函数变量)和一个普通变量名称具有同样的规范,都可以通过变量名来引用这个变量,但是函数变量名后面可以跟上括号和参数列表来进行函数调用。
new Function()的语法规范如下:
var funcName=new Function(p1,p2,...,pn,body);
参数的类型都是字符串,p1到pn表示所创建函数的参数名称列表,body表示所创建函数的函数体语句,funcName就是所创建函数的名称。可以不指定任何参数创建一个空函数,不指定funcName创建一个匿名函数。
需要注意的是,p1到pn是参数名称的列表,即p1不仅能代表一个参数,它也可以是一个逗号隔开的参数列表,例如下面的定义是等价的:
new Function("a", "b", "c", "return a+b+c")
new Function("a, b, c", "return a+b+c")
new Function("a,b", "c", "return a+b+c")
函数的本质是一个内部对象,由JavaScript解释器决定其运行方式。并且可直接在函数声明后面加上括号就表示创建完成后立即进行函数调用,例如:
var i=function (a,b){
return a+b;
}(1,2);
alert(i);
这段代码会显示变量i的值等于3。i是表示返回的值,而不是创建的函数,因为括号“(”比等号“=”有更高的优先级。
三、匿名函数和有名函数的区别
匿名函数必须先定义后调用,有名函数可以先调用,后定义。
A)匿名(这段语句将产生func未定义的错误)
<script>
func();
var func = function() {
alert(1);
}
< /script>
B)有名(输出1)
<script>
func();
function func() {
alert(1);
}
< /script>
这是因为JS解释器是分段分析执行的。并且,在同一段中,有名函数会优先被分析。并且同名函数后面的覆盖前面的。
而且,下面这段代码也是合法的:
<script>
function myfunc ()
{
alert("hello");
};
myfunc(); //这里调用myfunc,输出yeah而不是hello
function myfunc ()
{
alert("yeah");
};
myfunc(); //这里调用myfunc,输出yeah
</script>
如果要让上述代码的第一次调用输出“hello”,可以将它们分为两段:
<script>
function myfunc ()
{
alert("hello");
};
myfunc(); //这里调用myfunc,输出hello
< /script>
<script>
function myfunc ()
{
alert("yeah");
};
myfunc(); //这里调用myfunc,输出yeah
</script>
下面的代码输出“hello”
<script>
function myfunc ()
{
alert("hello");
};
< /script>
<script>
myfunc(); //输出“hello”
</script>
<script>
function myfunc ()
{
alert("yeah");
};
</script>
下面的代码输出“yeah”
<script>
function myfunc ()
{
alert("hello");
};
< /script>
<script>
function myfunc ()
{
alert("yeah");
};
</script>
<script>
myfunc(); //输出“yeah”
</script>
从上面对段的位置变化导致输出变化很清楚的解释了JS解释器分段分析执行的本质。
JAVA的文件上传遍一直是一个比较关注的问题,而且有几个NB东西提供了这个功能.
用的最多的算是三个(我就知道这三个)比较强的,一个是比较早的jspsmartupload,另一个是出身名族的commonupload,还有一个就是orellay的了.
我用的比较多是前两个,总的感觉是jspsmartuplod比较灵活,功能上更强一些(一点点吧),但是现在网上也不维护,也不能下载了,特别是 它上传的时候把上传文件放到内存里,所以上传文件的大小会和内存有关系.commonupload虽然没有提供很多API,但是它有比较灵活,它上传的过 程中会把上传的文件先写入磁盘,所以上传的大小只是带宽有关系,我尝试最大的上传文件的大小是700M,当然是本地测试:>
还有是就是在Linux/Unix系统上传文件的中文问题,我在下面的代码有了一些解决.
下面是前两种方式的上传代码:
try{
//取session 用户oid
int pid = userInfo.getUserId();
String sys_user_id = String.valueOf(pid);
//取init配置文件的参数值
String sitePhysicalPath = (String)init.getObject("SitePhysicalPath");
String saveDir = (String)init.getObject("InfoUploadDir");
String tempDir = (String)init.getObject("InfoUploadDir");
String fileMemo = ""; //文件说明
String fileName = null; //存储到数据库的文件名
String saveName = null; //存储到本地的文件名
String filePath = null; //存储到数据库的文件路径
String savePath = null; //存储到本地的文件路径
long fileSize = 0; //文件大小
int maxPostSize = -1;
int dinfo_upload_id = -1;
%>
<%
//初始化
mySmartUpload.initialize(pageContext);
//上载文件
mySmartUpload.upload();
//循环取得所有上载文件
for(int i=0; i<mySmartUpload.getFiles().getCount(); i++)
{
//取得上载文件
com.jspsmart.upload.File file = mySmartUpload.getFiles().getFile(i);
if(!file.isMissing())
{
fileName = file.getFileName();
//取得文件扩展名file.getFileExt()
try{
saveName = fileName.substring(fileName.lastIndexOf("."));
}catch(Exception e){
saveName = "";
}
//取得文件大小
fileSize = file.getSize();
//存储路径
String sql_id = " SELECT S_INFO_UPLOAD.nextval as seqid FROM dual ";
try{
Statement stmt = con.createStatement();
ResultSet rst = stmt.executeQuery(sql_id);
while(rst.next())
{
dinfo_upload_id = rst.getInt("seqid");
}
}catch(SQLException sqle){
return;
}
filePath = sitePhysicalPath + saveDir + Integer.toString(dinfo_upload_id) + saveName;
savePath = saveDir + Integer.toString(dinfo_upload_id) + saveName;
//存储文件到本地
file.saveAs(filePath);
//存储文件到数据库
switch(i)
{
case 0: fileMemo = (String)mySmartUpload.getRequest().getParameter("memo1"); break;
case 1: fileMemo = (String)mySmartUpload.getRequest().getParameter("memo2"); break;
case 2: fileMemo = (String)mySmartUpload.getRequest().getParameter("memo3"); break;
case 3: fileMemo = (String)mySmartUpload.getRequest().getParameter("memo4"); break;
case 4: fileMemo = (String)mySmartUpload.getRequest().getParameter("memo5"); break;
default: fileMemo = "";
}
String sql = " INSERT INTO info_upload (info_upload_id,sys_user_id,file_size,file_path,utime,deleted) "
+ " VALUES( " + Integer.toString(dinfo_upload_id) + "," + sys_user_id + "," + fileSize + ",'" + savePath + "', SYSDATE , 0 )" ;
sqlcmd cmd = new sqlcmd(con,sql);
//System.out.println(sql);
java.sql.PreparedStatement pstmt = null;
java.sql.Statement stmt = null;
//fileName = fileName.substring(0, fileName.indexOf("."));
String sql_cn = " UPDATE info_upload SET file_name=?,file_memo=? WHERE info_upload_id=? ";
java.io.ByteArrayInputStream bais_name = new java.io.ByteArrayInputStream(fileName.getBytes("ISO-8859-1"));
java.io.InputStreamReader isr_name = new java.io.InputStreamReader((InputStream)bais_name,"GBK");
java.io.ByteArrayInputStream bais_memo = new java.io.ByteArrayInputStream(fileMemo.getBytes("GBK"));
java.io.InputStreamReader isr_memo = new java.io.InputStreamReader((InputStream)bais_memo,"GBK");
try{
stmt = con.createStatement();
stmt.getConnection().setAutoCommit(false);
pstmt = con.prepareStatement(sql_cn);
pstmt.setCharacterStream(1, isr_name, fileName.length());
pstmt.setCharacterStream(2, isr_memo, fileMemo.length());
pstmt.setInt(3, dinfo_upload_id);
//System.out.println(sql_cn);
pstmt.execute();
stmt.executeUpdate("COMMIT");
}catch(Exception exce){
System.out.println(exce);
stmt.executeUpdate("ROLLBACK");
}
}
}
}catch(Exception e){
}
以上是jspsmart的方式,如果想要其它的方式,请下载全部源代码.
//upload_fileUpload.jsp
<%@ include file = "../../backgeneral.jsp"%>
<%@ contentType="text/html;charset=GBK" %>
<jsp:useBean id="userInfo" scope="session" class="com.ges.hbgov.UserInfo"/>
<%@ page import="org.apache.commons.fileupload.*" %>
<%
try{
//request.setCharacterEncoding("GBK");
//取session 用户oid
int pid = userInfo.getUserId();
String sys_user_id = String.valueOf(pid);
//取init配置文件的参数值
String sitePhysicalPath = (String)init.getObject("SitePhysicalPath");
String saveDir = (String)init.getObject("InfoUploadDir");
String tempDir = (String)init.getObject("InfoUploadDir");
String fileMemo = ""; //文件说明
String fileName = null; //存储到数据库的文件名
String saveName = null; //存储到本地的文件名
String filePath = null; //存储到本地的文件路径
String savePath = null; //存储到数据库的文件路径
long fileSize = 0; //文件大小
int maxPostSize = -1;
int dinfo_upload_id = -1;
%>
<%
DiskFileUpload df = new DiskFileUpload();
//设定上传文件大小
df.setSizeMax(maxPostSize);
//设定临时目录
df.setRepositoryPath(sitePhysicalPath + tempDir);
//取得request信息
List items = df.parseRequest(request);
Iterator iter = items.iterator();
int temp = 0;
FileItem tempItem = null;
while(iter.hasNext()){
temp++;
FileItem item = (FileItem)iter.next();
if(item.isFormField()) //取得文件说明信息
{
fileMemo = item.getString("GBK");
}
else
{ //取得上传文件信息
fileName = (String)item.getName();
try{
fileName = fileName.substring(fileName.lastIndexOf("//")+1);
fileName = fileName.substring(fileName.lastIndexOf("/")+1);
}catch(Exception e){
System.out.println(e);
}
fileSize = item.getSize();
tempItem = item;
}
if(temp == 2 && fileSize != 0)
{ //每两个iter存储一个上传文件
//得到info_title_id
String SQL_ID="select S_INFO_UPLOAD.nextval as seqid from dual";
try {
java.sql.Statement stmt = con.createStatement();
java.sql.ResultSet rst= stmt.executeQuery(SQL_ID);
while(rst.next())
{
dinfo_upload_id = rst.getInt("seqid");
}
}catch(SQLException e1){
return;
}
//取得文件扩展名
try{
saveName = fileName.substring(fileName.lastIndexOf("."));
}catch(Exception exc){
saveName = "";
}
filePath = sitePhysicalPath + saveDir + Integer.toString(dinfo_upload_id) + saveName;
//存储文件
java.io.File uploadFile = new java.io.File(filePath);
tempItem.write(uploadFile);
/*try{
FileOutputStream fos = new FileOutputStream(filePath);
InputStream is = tempItem.getInputStream();
byte[] b = new byte[1024];
int nRead;
long per = 0;
double percent = 0;
while((nRead = is.read(b, 0, 1024))>0){
fos.write(b, 0, nRead);
per += nRead;
percent = (double)per/fileSize;
session.setAttribute("percent",Double.toString(percent).substring(2,4));
session.setAttribute("filename",fileName);
}
is.close();
fos.close();
}catch(Exception e){
System.out.println(e);
}*/
savePath = saveDir + Integer.toString(dinfo_upload_id) + saveName;
/*/存储数据库
String sql = " INSERT INTO info_upload (info_upload_id,sys_user_id,file_name,file_memo,file_size,file_path,utime,deleted) "
+ " VALUES( " + Integer.toString(dinfo_upload_id) + "," + sys_user_id + ",'" + fileName + "','" + fileMemo + "'," + fileSize + ",'" + savePath + "', SYSDATE , 0 )" ;
sqlcmd cmd = new sqlcmd(con,sql);
*/
String sql = " INSERT INTO info_upload (info_upload_id,sys_user_id,file_size,file_path,utime,deleted) "
+ " VALUES( " + Integer.toString(dinfo_upload_id) + "," + sys_user_id + "," + fileSize + ",'" + savePath + "', SYSDATE , 0 )" ;
sqlcmd cmd = new sqlcmd(con,sql);
//System.out.println(sql);
java.sql.PreparedStatement pstmt = null;
java.sql.Statement stmt = null;
//fileName = fileName.substring(0, fileName.indexOf("."));
String sql_cn = " UPDATE info_upload SET file_name=?,file_memo=? WHERE info_upload_id=? ";
java.io.ByteArrayInputStream bais_name = new java.io.ByteArrayInputStream(fileName.getBytes("ISO-8859-1"));
java.io.InputStreamReader isr_name = new java.io.InputStreamReader((InputStream)bais_name,"GBK");
java.io.ByteArrayInputStream bais_memo = new java.io.ByteArrayInputStream(fileMemo.getBytes("GBK"));
java.io.InputStreamReader isr_memo = new java.io.InputStreamReader((InputStream)bais_memo,"GBK");
try{
stmt = con.createStatement();
stmt.getConnection().setAutoCommit(false);
pstmt = con.prepareStatement(sql_cn);
pstmt.setCharacterStream(1, isr_name, fileName.length());
pstmt.setCharacterStream(2, isr_memo, fileMemo.length());
pstmt.setInt(3, dinfo_upload_id);
//System.out.println(sql_cn);
pstmt.execute();
stmt.executeUpdate("COMMIT");
}catch(Exception exce){
System.out.println(exce);
stmt.executeUpdate("ROLLBACK");
}
temp = 0;
}
else if (temp == 2 && fileSize == 0) {temp = 0;}
}
//session.setAttribute("percent","ok");
}catch(Exception ex){
System.out.println(ex);
}
response.sendRedirect("list.jsp");
%>
//upload_jspSmart.jsp
<%@ include file = "../../backgeneral.jsp"%>
<%@ page language="java" import="java.util.*,java.sql.*,java.io.*"%>
<%@ page language="java" import="com.jspsmart.upload.*"%>
<%@ page language="java" import="com.ges.hbgov.*"%>
<jsp:useBean id="userInfo" scope="session" class="com.ges.hbgov.UserInfo"/>
<jsp:useBean id="mySmartUpload" scope="page" class="com.jspsmart.upload.SmartUpload" />
<%
//System.out.println("page=" + (String)session.getAttribute("SYS_USER_ID"));
if(!userInfo.Request(request)){
%>
<script language=javascript>
function relogin() {
this.parent.location.href="../../login.jsp";
}
relogin();
</script>
<%
}
%>
<%
try{
//取session 用户oid
int pid = userInfo.getUserId();
String sys_user_id = String.valueOf(pid);
//取init配置文件的参数值
String sitePhysicalPath = (String)init.getObject("SitePhysicalPath");
String saveDir = (String)init.getObject("InfoUploadDir");
String tempDir = (String)init.getObject("InfoUploadDir");
String fileMemo = ""; //文件说明
String fileName = null; //存储到数据库的文件名
String saveName = null; //存储到本地的文件名
String filePath = null; //存储到数据库的文件路径
String savePath = null; //存储到本地的文件路径
long fileSize = 0; //文件大小
int maxPostSize = -1;
int dinfo_upload_id = -1;
%>
<%
//初始化
mySmartUpload.initialize(pageContext);
//上载文件
mySmartUpload.upload();
//循环取得所有上载文件
for(int i=0; i<mySmartUpload.getFiles().getCount(); i++)
{
//取得上载文件
com.jspsmart.upload.File file = mySmartUpload.getFiles().getFile(i);
if(!file.isMissing())
{
fileName = file.getFileName();
//取得文件扩展名file.getFileExt()
try{
saveName = fileName.substring(fileName.lastIndexOf("."));
}catch(Exception e){
saveName = "";
}
//取得文件大小
fileSize = file.getSize();
//存储路径
String sql_id = " SELECT S_INFO_UPLOAD.nextval as seqid FROM dual ";
try{
Statement stmt = con.createStatement();
ResultSet rst = stmt.executeQuery(sql_id);
while(rst.next())
{
dinfo_upload_id = rst.getInt("seqid");
}
}catch(SQLException sqle){
return;
}
filePath = sitePhysicalPath + saveDir + Integer.toString(dinfo_upload_id) + saveName;
savePath = saveDir + Integer.toString(dinfo_upload_id) + saveName;
//存储文件到本地
file.saveAs(filePath);
//存储文件到数据库
switch(i)
{
case 0: fileMemo = (String)mySmartUpload.getRequest().getParameter("memo1"); break;
case 1: fileMemo = (String)mySmartUpload.getRequest().getParameter("memo2"); break;
case 2: fileMemo = (String)mySmartUpload.getRequest().getParameter("memo3"); break;
case 3: fileMemo = (String)mySmartUpload.getRequest().getParameter("memo4"); break;
case 4: fileMemo = (String)mySmartUpload.getRequest().getParameter("memo5"); break;
default: fileMemo = "";
}
String sql = " INSERT INTO info_upload (info_upload_id,sys_user_id,file_size,file_path,utime,deleted) "
+ " VALUES( " + Integer.toString(dinfo_upload_id) + "," + sys_user_id + "," + fileSize + ",'" + savePath + "', SYSDATE , 0 )" ;
sqlcmd cmd = new sqlcmd(con,sql);
//System.out.println(sql);
java.sql.PreparedStatement pstmt = null;
java.sql.Statement stmt = null;
//fileName = fileName.substring(0, fileName.indexOf("."));
String sql_cn = " UPDATE info_upload SET file_name=?,file_memo=? WHERE info_upload_id=? ";
java.io.ByteArrayInputStream bais_name = new java.io.ByteArrayInputStream(fileName.getBytes("ISO-8859-1"));
java.io.InputStreamReader isr_name = new java.io.InputStreamReader((InputStream)bais_name,"GBK");
java.io.ByteArrayInputStream bais_memo = new java.io.ByteArrayInputStream(fileMemo.getBytes("GBK"));
java.io.InputStreamReader isr_memo = new java.io.InputStreamReader((InputStream)bais_memo,"GBK");
try{
stmt = con.createStatement();
stmt.getConnection().setAutoCommit(false);
pstmt = con.prepareStatement(sql_cn);
pstmt.setCharacterStream(1, isr_name, fileName.length());
pstmt.setCharacterStream(2, isr_memo, fileMemo.length());
pstmt.setInt(3, dinfo_upload_id);
//System.out.println(sql_cn);
pstmt.execute();
stmt.executeUpdate("COMMIT");
}catch(Exception exce){
System.out.println(exce);
stmt.executeUpdate("ROLLBACK");
}
}
}
}catch(Exception e){
}
response.sendRedirect("list.jsp");
%>
最初,XML 语言仅仅是意图用来作为 HTML 语言的替代品而出现的,但是随着该语言的不断发展和完善,人们越来越发现它所具有的优点:例如标记语言可扩展,严格的语法规定,可使用有意义的标记,内容 存储和表现分离等等优势注定了该语言从诞生之日起就会走向辉煌。 XML 语言在成为 W3C 标准之后进入到了一个快速发展的时期,当然它本身所具有的一系列优点和优势也注定了各大技术厂商对它的偏爱,Java 作为软件行业的一种开发技术也迅速作出了反应,出现了多种对 XML 支持的工具,本文将会从这个角度对 Java 处理 XML 的几种主流技术进行介绍,希望能对您有所帮助。在这篇文章中,您将会得到以下信息:
- Java 提供了哪些优秀的类库及工具便于程序员对 XML 进行处理 ?
- 有了 DOM 了,其它工具类库还有必要么 ?
- 几个小例程带你快速了解这三种解析方式
Java 有哪些优秀的类库及工具便于程序员对 XML 进行处理 ?
- 大名鼎鼎的 DOM
- 绿色环保的 SAX
- 默默无闻的 Digester
XML 三种解析方式简介
大名鼎鼎的 DOM
说它大名鼎鼎可是一点不为过,DOM 是 W3C 处理 XML 的标准 API,它是许多其它与 XML 处理相关的标准的基础,不仅是 Java,其它诸如 Javascript,PHP,MS .NET 等等语言都实现了该标准, 成为了应用最为广泛的 XML 处理方式。当然,为了能提供更多更加强大的功能,Java 对于 DOM 直接扩展工具类有很多,比如很多 Java 程序员耳熟能详的 JDOM,DOM4J 等等, 它们基本上属于对 DOM 接口功能的扩充,保留了很多 DOM API 的特性,许多原本的 DOM 程序员甚至都没有任何障碍就熟练掌握了另外两者的使用,直观、易于操作的方式使它深受广大 Java 程序员的喜爱。
绿色环保的 SAX
SAX 的应运而生有它特殊的需要,为什么说它绿色环保呢,这是因为 SAX 使用了最少的系统资源和最快速的解析方式对 XML 处理提供了支持。 但随之而来繁琐的查找方式也给广大程序员带来许多困扰,常常令人头痛不已,同时它对 XPath 查询功能的支持,令人们对它又爱又恨。
默默无闻的 Digester:XML 的 JavaBean 化
Digester 是 apache 基金组织下的一个开源项目,笔者对它的了解源于对 Struts 框架的研究,是否有很多程序员想要一解各大开源框架的设计甚至想要自己写一个功能强大的框架时会碰到这样一个难题: 这些形形色色的用 XML 语言标记的框架配置文件,框架底层是用什么技术来解析呢? DOM 解析耗费时间,SAX 解析又过于繁琐,况且每次解析系统开销也会过大, 于是,大家想到需要用与 XML 结构相对应的 JavaBean 来装载这些信息,由此 Digester 应运而生。它的出现为 XML 转换为 JavaBean 对象的需求带来了方便的操作接口,使得更多的类似需求得到了比较完美的解决方法, 不再需要程序员自己实现此类繁琐的解析程序了。与此同时 SUN 也推出了 XML 和 JavaBean 转换工具类 JAXB,有兴趣的读者可以自行了解。
三种解析方式比较
DOM
优缺点:实现 W3C 标准,有多种编程语言支持这种解析方式,并且这种方法本身操作上简单快捷,十分易于初学者掌握。其处理方式是将 XML 整个作为类似树结构的方式读入内存中以便操作及解析,因此支持应用程序对 XML 数据的内容和结构进行修改,但是同时由于其需要在处理开始时将整个 XML 文件读入到内存中去进行分析,因此其在解析大数据量的 XML 文件时会遇到类似于内存泄露以及程序崩溃的风险,请对这点多加注意。
适用范围:小型 XML 文件解析、需要全解析或者大部分解析 XML、需要修改 XML 树内容以生成自己的对象模型
SAX
SAX 从根本上解决了 DOM 在解析 XML 文档时产生的占用大量资源的问题。其实现是通过类似于流解析的技术,通读整个 XML 文档树,通过事件处理器来响应程序员对于 XML 数据解析的需求。由于其不需要将整个 XML 文档读入内存当中,它对系统资源的节省是十分显而易见的,它在一些需要处理大型 XML 文档以及性能要求较高的场合有起了十分重要的作用。支持 XPath 查询的 SAX 使得开发人员更加灵活,处理起 XML 来更加的得心应手。但是同时,其仍然有一些不足之处也困扰广大的开发人员:首先是它十分复杂的 API 接口令人望而生畏,其次由于其是属于类似流解析的文件扫描方式,因此不支持应用程序对于 XML 树内容结构等的修改,可能会有不便之处。
适用范围:大型 XML 文件解析、只需要部分解析或者只想取得部分 XML 树内容、有 XPath 查询需求、有自己生成特定 XML 树对象模型的需求
Digester/JAXB
优缺点 : 由于其是在上述两者的基础上衍生出来的工具类,为的是满足将 XML 转换为 JavaBean 的特殊需求,故而没有什么特别明显的优缺点。作为大名鼎鼎的开源框架 Struts 的 XML 解析工具 Digester,为我们带来了将 XML 转换为 JavaBean 的可靠方法。
适用范围 : 有将 XML 文档直接转换为 JavaBean 需求。
应用示例
下面给出一段用于解析的 XML 片段:
清单 1. XML 片段
<?xml version="1.0" encoding="UTF-8"?> <books> <book id="001"> <title>Harry Potter</title> <author>J K. Rowling</author> </book> <book id="002"> <title>Learning XML</title> <author>Erik T. Ray</author> </book> </books>
DOM 解析 XML
Java 中的 DOM 接口简介: JDK 中的 DOM API 遵循 W3C DOM 规范,其中 org.w3c.dom 包提供了 Document、DocumentType、Node、NodeList、Element 等接口,这些接口均是访问 DOM 文档所必须的。我们可以利用这些接口创建、遍历、修改 DOM 文档。
javax.xml.parsers 包中的 DoumentBuilder 和 DocumentBuilderFactory 用于解析 XML 文档生成对应的 DOM Document 对象。
javax.xml.transform.dom 和 javax.xml.transform.stream 包中 DOMSource 类和 StreamSource 类,用于将更新后的 DOM 文档写入 XML 文件。
下面给出一个运用 DOM 解析 XML 的例子:
清单 2. DOM 解析 XML
import java.io.File; import java.io.IOException; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; public class DOMParser { DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); //Load and parse XML file into DOM public Document parse(String filePath) { Document document = null; try { //DOM parser instance DocumentBuilder builder = builderFactory.newDocumentBuilder(); //parse an XML file into a DOM tree document = builder.parse(new File(filePath)); } catch (ParserConfigurationException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return document; } public static void main(String[] args) { DOMParser parser = new DOMParser(); Document document = parser.parse("books.xml"); //get root element Element rootElement = document.getDocumentElement(); //traverse child elements NodeList nodes = rootElement.getChildNodes(); for (int i=0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (node.getNodeType() == Node.ELEMENT_NODE) { Element child = (Element) node; //process child element } } NodeList nodeList = rootElement.getElementsByTagName("book"); if(nodeList != null) { for (int i = 0 ; i < nodeList.getLength(); i++) { Element element = (Element)nodeList.item(i); String id = element.getAttribute("id"); } } } }
在上面的例子中,DOMParser 的 Parse() 方法负责解析 XML 文件并生成对应的 DOM Document 对象。其中 DocumentBuilderFactory 用于生成 DOM 文档解析器以便解析 XML 文档。 在获取了 XML 文件对应的 Document 对象之后,我们可以调用一系列的 API 方便的对文档对象模型中的元素进行访问和处理。 需要注意的是调用 Element 对象的 getChildNodes() 方法时将返回其下所有的子节点,其中包括空白节点,因此需要在处理子 Element 之前对节点类型加以判断。
可以看出 DOM 解析 XML 易于开发,只需要通过解析器建立起 XML 对应的 DOM 树型结构后便可以方便的使用 API 对节点进行访问和处理,支持节点的删除和修改等。 但是 DOM 解析 XML 文件时会将整个 XML 文件的内容解析成树型结构存放在内存中,因此不适合用 DOM 解析很大的 XML 文件。
SAX 解析 XML
与 DOM 建立树形结构的方式不同,SAX 采用事件模型来解析 XML 文档,是解析 XML 文档的一种更快速、更轻量的方法。 利用 SAX 可以对 XML 文档进行有选择的解析和访问,而不必像 DOM 那样加载整个文档,因此它对内存的要求较低。 但 SAX 对 XML 文档的解析为一次性读取,不创建任何文档对象,很难同时访问文档中的多处数据。
下面是一个 SAX 解析 XML 的例子:
清单 3. SAX 解析 XML
import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.DefaultHandler; import org.xml.sax.helpers.XMLReaderFactory; public class SAXParser { class BookHandler extends DefaultHandler { private List<String> nameList; private boolean title = false; public List<String> getNameList() { return nameList; } // Called at start of an XML document @Override public void startDocument() throws SAXException { System.out.println("Start parsing document..."); nameList = new ArrayList<String>(); } // Called at end of an XML document @Override public void endDocument() throws SAXException { System.out.println("End"); } /** * Start processing of an element. * @param namespaceURI Namespace URI * @param localName The local name, without prefix * @param qName The qualified name, with prefix * @param atts The attributes of the element */ @Override public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException { // Using qualified name because we are not using xmlns prefixes here. if (qName.equals("title")) { title = true; } } @Override public void endElement(String namespaceURI, String localName, String qName) throws SAXException { // End of processing current element if (title) { title = false; } } @Override public void characters(char[] ch, int start, int length) { // Processing character data inside an element if (title) { String bookTitle = new String(ch, start, length); System.out.println("Book title: " + bookTitle); nameList.add(bookTitle); } } } public static void main(String[] args) throws SAXException, IOException { XMLReader parser = XMLReaderFactory.createXMLReader(); BookHandler bookHandler = (new SAXParser()).new BookHandler(); parser.setContentHandler(bookHandler); parser.parse("books.xml"); System.out.println(bookHandler.getNameList()); } }
SAX 解析器接口和事件处理器接口定义在 org.xml.sax 包中。主要的接口包括 ContentHandler、DTDHandler、EntityResolver 及 ErrorHandler。 其中 ContentHandler 是主要的处理器接口,用于处理基本的文档解析事件;DTDHandler 和 EntityResolver 接口用于处理与 DTD 验证和实体解析相关的事件; ErrorHandler 是基本的错误处理接口。DefaultHandler 类实现了上述四个事件处理接口。上面的例子中 BookHandler 继承了 DefaultHandler 类, 并覆盖了其中的五个回调方法 startDocument()、endDocument()、startElement()、endElement() 及 characters() 以加入自己的事件处理逻辑。
Digester 解析 XML
为了满足将 XML 转换为 JavaBean 的特殊需求,Apache 旗下的一个名为 Digester 的工具为我们提供了这么一个选择。由于最终是将 XML 转化为 JavaBean 存储在内存当中, 故而解析性能等方面其实与使用者并没有多大关系。解析的关键在于用以匹配 XML 的模式以及规则等,由于该工具较为复杂,限于篇幅,作者只能给予简单的介绍。
下面是一个 Digester 解析 XML 的例子片段:
清单 4. Digester 解析 XML
// 定义要解析的 XML 的路径,并初始化工具类 File input = new File("books.xml"); Digester digester = new Digester(); // 如果碰到了 <books> 这个标签,应该初始化 test.myBean.Books 这个 JavaBean 并填装相关内容 digester.addObjectCreate("books", "test.myBean.Books"); digester.addSetProperties("books"); // 如果碰到了 <books/book> 这个标签,同上初始化 test.myBean.Book 这个 JavaBean digester.addObjectCreate("books/book", "test.myBean.Book"); digester.addSetProperties("books/book"); // 通过调用上面已经初始化过的 JavaBean 的 addBook() 方法来把多个 <books/book> 加到一个集合中 digester.addSetNext("books/book", "addBook", "test.myBean.Book"); // 定义好了上面的解析规则后,就可以开始进行解析工作了 Books books = (Books) digester.parse(input);
上述代码简单的向读者展示了 Digester 处理 XML 的一些要点,主要是说明了一些模式以及规则的匹配。 简言之,Digester 就是一种用来把一个 XML 转化为一个与该 XML 结构类似的 JavaBean。你可以把 XML 根元素想象成一个 JavaBean, 该根元素的 attribute 就是这个 JavaBean 的各种 Field,当该根元素有其他子 tag 时,又要把这个子 tag 想象成一个个新的 XML,将其视为一个新的 JavaBean, 并作为一个 Field 加入到父 Bean 当中,然后以此类推,通过循环的方式将整个 XML 进行解析。
结束语
本文介绍了 Java 解析 XML 的三种常用技术,其中 DOM 易于上手,程序易于理解,但缺点在于占用内存大,不适合于解析较大的 XML 文件; SAX 基于事件模型占用系统资源少,能够胜任较大的 XML 文件解析,但解析过程较为繁琐查找元素不方便; Digester/JAXB 基于上述两种技术衍生而来。文中的实例向读者展示了三种 API 的基本使用方法, 在实际开发过程中使用那种技术解析 XML 更好要依据各自的优缺点视具体情况而定。
第一日:初尝禁果 【上帝说:“要有光!”便有了光】
万物生灵、阳光雨露盖源于造物之初的天工开物,我们无法想象上帝创造光明之前的世界模样。但幸运的是,前端开发没有神祗般的诡魅。这个技术工种 的孕育、定型、发展自有轨迹,也颇有渊源,当然,这非常容易理解。不严格的讲,在杨致远和费罗在斯坦福大学的机房里撺掇出Yahoo!时,Web前端技术 就已经开始进入公众视野,只不过当时没有一个响亮的名字。从那时起,“基于浏览器端的开发”就成了软件开发的新的分支,这也是Web前端技术的核心,即不 论何时何地何种系统以及怎样的设备,但凡基于浏览器,都是Web前端开发的范畴(当然,这个定义很狭隘,下文会提到)。
在2000年之后浏览器技术渐渐成熟,Web产品也越来越丰富,中国有大批年轻人开始接触互联网,有一点需要注意,大部分人接触互联网不是始于 对浏览器功能的好奇,而是被浏览器窗口内的丰富内容所吸引,我们的思维模式从一开始就被限制在一个小窗口之内,以至于很长时间内我们将“视觉”认为是一种 “功能”,Web产品无非是用来展现信息之用。起初的入行者无一例外对“视觉”的关注超过了对“内容”的重视,先让页面看起来漂亮,去关注 html/css,沿着“视觉呈现”的思路,继续深入下去。因此,这类人是被“视觉”所吸引,从切页面入行,着迷于结构化的html和书写工整的css, 喜欢简洁优雅的UI和工整的页面设计,之后开始接触视觉特效,并使用jQuery来实现视觉特效,以此为线索,开始深入研究Dom、Bom和浏览器的渲染 机制等,html/css在这些人手中就像进攻兵器,而JavaScript则更如防守的盾牌。
还有另外一群人从另一条道路接触Web前端,即工程师转行做前端,他们有较多的后台语言开发背景,从读写数据开始,渐渐触及浏览器端,接触 JavaScript库,起初是在html代码上加js逻辑,后来开始涉及html和css,他们喜欢OO、逻辑清晰、结构悦目的代码,更关注界面背后的 “程序语言”和数据逻辑。html/css在这些人手中则更像盾牌,而JavaScript更如进攻的兵器。
应当说这两类人是互补的,他们各自了解浏览器本质的一部分,一拨人对渲染引擎了如指掌,另一拨人则将JS引擎奉为至宝,其实任何一部分的优势发 挥出来都能做出精品。大部分前端工程师都能从这两条渊源中找到自己的影子。但,这两类人的思维模式和观点是如此不同,以至于形成了一些不必要的对抗,比如 在某些公司,干脆将Web前端技术一分为二,“切页面的”和“写js的”。这样做看上去明确了分工提高了效率,但他对员工的职业发展带来巨大伤害。在第二 日“科班秀才”中会有进一步讨论。
我应该属于第二类,即在学校正儿八经的学习C/Java和C#之类,以为大学毕业后能去做ERP软件、桌面软件或者进某些通信公司写TCP /IP相关的程序。校园招聘时选择了中国雅虎,因为当年(08年)雅虎还是有一点儿名气,而且我听说雅虎比较算技术流的公司……自此就上了贼船,一发不可 收拾。
在雅虎的这段时间,我有幸接触到一股正气凛然的技术流派,也形成了我对前端技术的一些基本看法,这些基本观点一直影响我至今。
【优雅的学院派】
当年雅虎的技术流派正如日中天,拥有众多“之父”级的高人,所营造出的Hack氛围实在让人陶醉的无法自拔,那段时间我甚至宁愿加班到深夜阅读 海量的文档和源代码,感觉真的很舒服,我深深的被雅虎工程师这种低调务实、精工细琢的“服务精神”所打动,而这种不起眼的优秀品质很大程度的影响雅虎产品 的用户体验和高质量的技术输出。那么,何谓“服务精神”?即你所做的东西是服务于人的,要么是产品客户、要么是接手你项目的人、要么是使用你开发的功能的 人,所以技术文档成为伴随代码的标配。因此,工程师之间通过代码就能做到心有灵犀的沟通。这是工程师的一项基本素质,即,思路清晰的完成项目,且配备了有 价值的技术文档,如果你的程序是给其他程序员用的,则更要如此,就好比你制造一款家电都要配备说明书一样。因此,YDN成了当时最受全球程序员最喜爱的技 术文档库,这种优雅务实的“学院气息”让人感觉独具魅力。
让人感觉奇怪的是,在中文社区始终未见这种学院派。甚至在具有先天开源优势的Web前端技术社区里也是波澜不惊,可见写一篇好的技术文案真的比 登天还难。我所见到的大部分所谓文档索性把代码里输出数据的语句块拷贝粘贴出来,至于为什么数据格式要设计成这样、如果字段有修改怎么做、编码解码要求如 何等等关键信息只字不提,或者开发者也没想过这些问题呢。因此,我们一直在强调代码的质量和可维护性,但一直以来都未见效,盖源于缺少这种“服务”意识的 灌输。这种意识在下文中还会多次提到,因为它能影响你做事的每个细节,是最应当首先突破的思想纠结。
除了意识问题,另一方面是技术问题,即文笔。这也是工程师最瞧不上眼的问题,难以置信这竟然是阻碍工程师突破瓶颈的关键所在。我已看到过数不清 的人在晋升这道关卡吃了大亏,很多工程师技术实力很强,但就是表达不出来,要么罗列一大堆信息毫无重点、要么毫无趣味的讲代码细节,不知云云。除非你走狗 屎运碰到一个懂技术的老板,否则真的没办法逃脱码农的宿命。但大部分人还振振有词不以为然。而在Web前端开发领域情况更甚。前端工程师是最喜欢搞重构 的,但在快节奏的需求面前,你很难用“提高了可维护性”、“提升了性能”这类虚无缥缈的词藻为自己争取到时间来搞重构,说的露骨一点,可能你真的对某次重 构带来的实际价值无法量化,只是“感觉代码更整洁了”而已。我会在下文的“伪架构”中会展开分析前端工程师的这种浮躁献媚的技术情结。而这正是前端工程师 最欠缺的素质之一:用数据说话,用严谨科学的论据来支撑你的观点,老板不傻,有价值的东西当然会让你去做。
当然,情况不总是这么糟糕,我们看到中文社区中已经锻炼出了很多写手,他们在用高质量的文字推销自己的技术理念,这是一个好兆头,好的文笔是可 以锻炼出来的。而在职场,特别是对前端工程师这个特殊职位来讲,这种基本技能可以帮你反思梳理需求的轻重缓急,从凌乱的需求中把握七寸所在。因为当你开始 认真写一封邮件的时候,这种思考已经包含其中了。
所以,雅虎技术的推销是相对成功和远播的。关键在于两方面,扎实的技术功底和高超的写手。而真正的技术大牛一定是集两者与一身,不仅钻研剑道,还能产出秘籍。这也是Yahoo!优雅的学院派气息的动力源泉。国内很多技术团体想在这方面有所建树,应当首先想清楚这一点。
【规范的破与立 1】
雅虎的技术运作非常规范,刚才已经提到,包括技术、组织、文化,一切看起来有模有样,也堪称标杆,自然成了国内很多技术团队和社区的效仿对象。一时间各种“规范“成风、各色“标准“大行其道,结果是质量参差不齐。
我们到底需要什么样的规范?雅虎的技术规范到底有何种魔力?以何种思路构建的规范才是货真价实的?规范有着怎样的生命周期?想清楚这些问题,能很大程度减轻很多Web前端工程师的思想负担,看清一部分技术本质,避免盲目跟风。
我们的确需要规范,但好的规范一定是务实的,一定是“解决问题“的。比如针对项目构建的DPL可以收纳公用的视觉元件以减少重复开发、规定某 OPOA项目的事件分发原则以确立增量开发的代码惯性。反之,糟糕的规范却显得过于“抽象“,比如页面性能指标、响应式设计原则。另外,尽管他山之石可以 攻玉,但拿来主义有一个大前提,就是你了解你的项目的关键问题,你要优先解决的是些关键问题,而外来规范正好能解决你的问题。因此规范是一本案头手册,是 一揽子问题的解决方案,应当是“字典”,而不是“教程“。可见规范的源头是“问题”。所以,当你想用CoffeeScript重构你的项目时、当你想引入 CommonJS规范时、当你想在页面中揉进Bootstrap时、当你打算重复造轮子搞一套JS库时、当你想重写一套assets打包工具时,想想这些 东东解决了你的什么问题?会不会带来新的问题、把事情搞复杂了?还是为了尝鲜?或者为了在简历中堂而皇之的写上使用并精通各种新技术?
规范之立应当有动因,动因来源于项目需求,项目需求则来自对产品的理解和把握,这是Web前端初级工程师走向中级甚至高级的一次重要蜕变,软件 工程领域早就有“架构师”角色,而架构师往往存在于项目需求分析和概设、详设阶段。我看到的情况是,Web前端工程师的思维过多的限制在“界面”之内,向 前和产品需求离的太远(认为这是视觉设计师的事)、向后和数据逻辑又隔离开来(认为这是后台工程师该干的事),因此前端规范也大都泛泛,无关项目痛痒,成 了玩具。
雅虎技术规范的优秀之初在于它们解决问题。所以,学习使用规范应当多问一句,“他们为什么这样做?”其实,想清楚这些问题时,脑海中自然形成了一种“遇山开山”的创造性思维。
【规范的破与立 2】
如果说新技术的尝鲜缺少针对性,但至少满足程序员的某种洁癖和快感,那么“负担”从何而来呢?对于初学者来说,有价值学习资料可能只有这些规范,如果说规范价值不大,那又当从何入手呢?
刚才我说的不是依赖于规范,而是对规范的反思,摆脱规范灌输给我们的思维定势。新人们大概是看了Wiki中的很多指标、结论、实践,在做项目之 初就附加了不少“八股式”的负担,甚至影响我们对项目关键需求和关键问题的洞察力和判断力,负担过重就无法轻装上阵,Wiki中提到的这些指标和规范是结 论性的,是大量的实践之后得出的,也只有经历过大量实践才会真正理解这些结论,比如DomReady时间和http请求数是否有因果关系,http请求数 增加是否真的会导致页面性能下降,什么条件下会导致性能下降?我们从那些条文和结论中无法找到答案。
举个具体的例子,Kissy刚刚出了DPL,也是一大堆结论,比如他的布局就采用了经典的双飞翼,使用容器浮动来实现,那么,这种做法就是不可 撼动的“标准”吗?看看淘宝车险首页,布局容器齐刷刷的inline-block,只要顶层容器去掉宽度,布局容器自身就能根据浏览器宽度调整自然水平/ 垂直排列,轻易的适应终端宽度了。
再比如,淘宝旅行计划项目中的部署方式,也没有完全使用Loader管理依赖,而是将依赖层级做的很少,业务逻辑使用脚本来合并,这样就可以更容易在build环节加入语法检查和代码风格检查。
类似这种摆脱原有编程思维,有针对性的用新思路新方法解决问题的做法显然让人感觉更加清爽,编程的乐趣也正体现在打破常规的快感之中,小马曾经 说过:“制造规范是为了打破规范”,万不要因为这些规范标准加重负担,导致开始做一个简单页面时也显得缩手缩脚,无法放开身手。大胆的动手实践,才能真正 得出属于自己的“结论 “和“标准“,才会真正深刻理解那些“结论”的意义所在。代码写的多了,自然熟能生巧,也容易形成成熟的技术观点。
在这个过程中,我们唯一的对手是懒惰,惰于思考,就无法真正发现问题,自然形不成自己的观点。还是那句话,任何规范、方法、结论、实践都是为了 解决项目中的问题的,所以,我们所接触到那些看似“八股文”式的规范标准也是为了解决某些问题而提出的,想清楚这些问题,理解方法论背后的“因“,内心自 然有“果”。
因此,“着眼当下、对症下药”的品质就显得弥足珍贵了,比如,双飞翼布局方法是为了解决一套(html)代码适应多种布局设计,这里的布局相对 于固定的产品来说也是固定的,而无针对终端的自适应(适用于移动端的榻榻米布局似乎还没有最佳实践)。这是双飞翼产生的背景,如今终端环境较之5年前已经 翻天覆地,问题早已不在“多种布局”上,而在“终端适应“上,这才是我们面临的问题,需要我们给出新的技术方案。
所以,勤于思考,轻装上阵,大胆实践,勇于创新,发掘问题所在,实打实的解决(潜在)问题,这才是我们真正需要的能力。放下思维定势枷锁,也会有一种豁然开朗的感觉。
第二日:科班秀才
【秀才仕途】
Web前端工程师是一个特别的岗位,只存在于互联网领域。最近几年随着互联网产业的火爆,对前端工程师的需求量暴增,兵源几近枯竭。各大公司技术掌门一定都有过类似的苦恼:“招一个靠谱的前端工程师、难于上青天”。
我想,一部分原因是,当前不少入道的前端工程师大都是转行而来,毕竟,正儿八经的学校里也不会教这玩意,觉得“切页面”有啥好教的,甚至不觉得 html/css是一门语言。转行这事自不必详说,大家也各自瞄准当前市场需求,造成的现象是,初级前端工程师堆成山,中高级人才却一将难求,计算机系的 科班出身就更加凤毛麟角了。一方面反映了教育部门的后知后觉,另一方面也体现了大部分人急功近利的跟风。当然最重要的原因是,所谓中国“第一代前端工程 师”并未做好布道的工作。导致大家对于基础和潜力的态度从之前的忽视演变为如今的蔑视。所谓基础,就是在大学上的那些计算机基础课。所谓潜力,就是戒骄戒 躁的务实作风。这些会在后文中多次提到。
对于科班出身的莘莘学苗来说,根正苗红本身就是一种优势,事实证明,这些人在前端技术上的成长轨迹有一定的套路,而且大都能如期的突破技能瓶颈。从一个人大学毕业到他最满意的工作状态,中间会经过几个阶段。
前2年是学习技能的阶段,这个阶段主要精力放在专业技能的提升上,2年内起码要赶上平均水平,即所谓“中级“,在这个阶段的人通常对软技能不怎 么关注,沟通能力达不到平均水平,基本上是来啥活干啥活,干不完就加班的这种,对需求的合理性不甚理解,对项目也没什么把控,尽管在技能上有提高的空间, 也不是公司最需要的人,但有不少成长空间。
工作2-3年的人在前端技能上趋于稳定,也就是技能上的第一次瓶颈,这种人干活熟练,切页面可能也很快,代码看上去也比较规范,属于熟练工,开 始注重沟通技巧和一些职业技能的积累,比如带人带项目,至少有这方面的意识,并有过推动项目、和业务方pk需求的经历,这就达到了中级应当具备的职业技 能,但应当注意的是,这时最容易出现偏科的情况,特别是对于那些“专门切页面的“和“专门写脚本的“人,毕竟html/css/js三者不分彼此,三者是 一个合格前端工程师都必须要掌握的。如果你觉察到自身有偏废的嫌疑,则要小心了,要清楚的了解自身的差距,并意识到瓶颈的存在,为过渡到“中级“的打下基 础。
过了这道坎之后,工作3年以上的人大部分技能也趋稳,有些人对前端新技术有钻研,能够熟练应对日常工作,软技能也ok,具备有针对性的“拿来主 义“,代码也具有一定的架构性,开始突破“代码民工”的这一层瓶颈,对团队气氛、培训、工作环境有个性化的要求,一般来讲,这种人是典型的具有潜力的“中 级”工程师,但很快会遇到职业发展中的第二个技术瓶颈。
有少数工作3年或4年以上,在不断寻求新的技能上的突破,最明显的一点体现是,开始关注“底层协议”,即HTTP、第三方应用、系统对接、制造 工具、工作流程等,这时思考的重点已经脱离了“切页面”,变为“出方案“,比如要架设一个站点,能够搭建站点框架,预见站点后续(前端)开发中的所有风 险,并一一给出解决方案。项目后续开发遇到问题只要翻阅你提供的“手册”即能找到答案。这种人是标准的“高级”Web前端工程师。
出方案是一件挺难的事情,它要求一个工程师同时具备经验、技术、气场等诸多硬技能。尤其是对技术底子的要求非常高。
【半路出家】
那么,转行做前端的人又当如何呢?其实发展轨迹和科班秀才们非常类似,只是时间跨度可能会长一些,你要花更多的精力、做更多的项目、更多的反思和总结才能理解某个知识点的本质(比如HTTP协议)。当然这只是一般情况。
此外,这些人还需要摆脱很多思维定势的禁锢。这里我推荐大家阅读阿当的《Web前端开发修炼之道》。当然,如果你有一个靠谱的师兄带你入道,自然幸运万倍。
但不管怎样,我始终认为应当秉承兴趣第一的原则,不管你是误打误撞、还是意欲为之,不管你是科班秀才、还是半路出家,兴趣始终应当是第一原则, 然后才是你“想做好“。我对自己的要求无法强加于人,所以很多业界大牛在回顾自己成功之路时,提到最多的是:“热爱你的工作、拥抱它给你带来的挑战”。 N.C.Zakas曾经这样勉励大家:
“我对Web开发人员最大的建议就是:热爱你的工作。热爱跨浏览器开发带来的挑战、热爱互联网技术的种种异端,热爱业内的同行,热爱你的 工 具。互联网发展太快了,如果你不热爱它的话,不可能跟上它的步伐。这意味着你必须多阅读,多动手,保证自己的才能与日俱增。下了班也不能闲着,要做一 些对自己有用的 事儿。可以参与一些开源软件的开发,读读好书,看看牛人的博客。经常参加一些会议,看看别人都在干什么。要想让自己快速成长,有很多事儿 可以去做,而且付出一定会有回报。“
第三日,幸福感
【先精通十行?!】
兴趣第一,听上去很美,但现实却不总是这么酷。练就了一身本领,那也要找到对口的怪物来打一打才过瘾。
自然,每个人都想做出好东西,每个工程师也都渴求这样的机遇,用层次分明的设计、漂亮优雅的代码、精妙的细节雕琢,做出美观、安全、实用耐用的 产品,不过现实是如此残酷,以至于工程师们一直都缺乏对产品的归属感。作为前端工程师,如何才能在江湖中把握住前进方向、步步走高?毕竟,在职位繁杂的大 公司,缺乏人性化的工作流程影响着工程师的工作幸福感。产品从设计之初、到技术方案评审、再到实现,处处充满了妥协,大部分产品都是杂交的产物,人与人相 互掣肘,每个人都对产品不满意……,大跃进式的敏捷开发早就被证明百害无一利。但,或许这就是成长的代价。年轻的工程师需要更多的了解需求和设计、产品经 理更要懂得软件迭代规律。对于前端工程师来讲更是如此,多学习交互设计和UI,多了解网络协议和软件迭代模型,更能帮助前端工程师和需求方沟通、和后台的 衔接、以及控制版本的迭代。
说来奇怪,前端工程师不是写html/css/js的吗,搞懂那些边缘知识有什么用?《Web前端开发修炼之道》中也提到,精通一行需要先精通十行。这里我来解释一下原因。
作为交互设计师的下游,前端工程师学需要习设计知识是很容易理解的,因为它能帮助你更准确的理解设计师的意图,在原型不完整的时候也能正确的反 馈设计缺陷,将问题阻挡在设计的环节,会大大减少UI bug数量,比如说,设计师会给出理想状态下的容器样式,却往往忽略了文字溢出折行、长连续字符、 容器宽高是否适应内容尺寸变化而变化,溢出部分是作截字还是隐藏等诸多细节,因为设计师不懂“边界值测试”的道理,而这些问题往往在测试阶段才被发现,所 以,如果能在拿到UI设计稿时就提醒设计师补充完整这些场景,自然减少测试回归次数。
另外,前端工程师必须要了解网络协议,原因很简单,我们做的产品运行在Web上。很多依赖于Ajax的实现,只有前端工程师才会提出实现方案, 产品经理不了解技术瓶颈,后台工程师更不会在意客户端的用户体验,举个简单的例子:通过JS实现一个Ajax,如果Ajax抓取的数据源是一个302跳 转,则需要在JS程序中多做一些事情,这就需要前端工程师了解一些HTTP协议。应当说,这是很常见的一个场景。
那么,为什么说前端工程师也要关注代码版本控制呢?因为web开发和软件开发本质无异,同样具有迭代周期,需求不是一揽子提完、一口气开发完 的,是有步骤的开发,因此,每次上线开发哪些功能、为后续扩展功能留足哪些接口、代码在可扩展和可维护性上应当作哪些考虑……,这些应当是每个工程师关注 的事情,所谓迭代就是指这种需求的叠加,这是软件开发的常态,也是web开发的常态,刚开始,前端工程师总会不断抱怨没完没了的需求,代码起初还算干净, 但很快就越来越乱,代码的版本管理对于Web前端工程师来说有些困难,这也使得大部分前端工程师很难上档次,从这个角度讲,前端工程师是需要向后台工程师 学习的,他们的开发量不比前端少,维护代码的能力要超过前端工程师。另外,对于刚入行的前端工程师,心态要放对,提需求是产品经理的职责所在,整理出有价 值的需求是交互设计师的职责所在,将需求作版本控制分步实现是前端工程师的职责所在,前端工程师没必要去抱怨产品经理提一大堆没规律的需求,而更应当去理 解需求缘由,将需求提炼成UC(用例),让需求在自己手中可控制。只是多数前端工程师缺乏提炼、整理需求的能力,一味的在接需求,才会搞的手忙脚乱,带着 情绪堆代码。
所以,只有练就了一身本领,才会更有目标的去寻找对产品的责任感和对团队的归属感,不要误以为能切出漂亮的页面就是能力的提高,纯粹的写代码每 个人都差不多的,要成为合格的工程师,眼界要进一步放开,前端工程师能做的,不仅仅是切页面而已,作一个精品项目,一定不乏专业的过程把控,这也是大多数 人最易忽略的地方。
【励志之本】
其实,除了个人需要明确努力的方向,每个人都更渴望身处一个好团队,谁都不希望有猪一样的队友。我们都很羡慕处身这样的团队,可以放心的将精力 放在纯粹的技术上,身边每个人都自觉的补充文档注释,代码也层次清晰解偶充分重用率高,精妙的设计实现可以更快的传播,bug得到的改进建议也是务实专业 的,技术在这种良性互动中价值倍增。我想这也算是好团队的一种境界了,这有赖于团队成员水平水涨船高。不过,反观Yahoo的成长之路,他们的技术积淀也 是靠点滴的积累,其实他们当初的状况不比现在的我们好哪去,10年的进化,才造就了Yahoo技术团队的专业性和Hack精神,我们每个人才刚刚起步而 已。为了积攒工作中的幸福感,多付出一些是值得的。
但我猜,你现在的处境一定不会太过乐观,产品乱提需求、一句话的PRD、不被重视,被生硬的当作“资源“……反正,情况就是这么个情况,要么你 选择抱怨下去,要么想办法去改变。“积极主动“是源自内心的一种坚韧品质,也是励志之本,有些人在现实中被磨平了理想,有些人却在黑暗森林中找到了方向, 这就是犬儒主义和英雄气概之间的差别。这自不必详说,因为这让我想起了“大长今”,这简直就是前端工程师的励志典范:“这是一个可怕的环境,足以消磨任何 人的斗志和信念,所有来这里的人都变得麻木和无所作为,‘多栽轩‘恶劣的环境没有改变长今,但长今却改变了‘多栽轩‘所有的人“。
如果你想做到“资深”,就一定要想清楚这一点,因为你是团队的顶梁柱(业务),也是幸福感的源头(士气)。
第四日,架构和伪架构
【代码设计的本质】
读到这里,你不禁会问,前端领域存在“架构师”吗?这个问题会在后面的“码农的宿命”中展开解释。这里先说下代码架构的一些琐事吧。
什么是架构?架构是由“架”和“构”组成,架,即元件,构,即连接件。因此,架构即是将总体分解为单元,然后定义单元之间的连接方式。架构的含 义源自禅宗,而禅宗的基本信条则之一就是真理是无法用语言来描述的。这个基本信条有其背景,即语言具有某种抽象性。而人们对这种抽象性的悟道则直接影响对 事物的看法,进而决定了对客观世界的分解方法。
而在编程语言中,同样存在这种禅宗所隐喻的悖论。在面向对象的教科书中,通常举一些显而易见的例子,比如“水果”是一个类,包含有苹果、桔子、 香蕉等实例,“蔬菜”也是一个类,包含白菜、冬瓜、茄子等实例。这两个类之间并无交集,因此很容易理解。但实际项目中情况要复杂的多,比如两个图书类目 “文学”和“历史”,那么“明朝那些事”应当是“文学”类的实例还是“历史”类的实例呢?即一旦用语言说出了某一事物,即人为的割裂了世界,于是就会陷入 迷途。这在程序设计领域情况更甚,也是造成混乱的主要根源,也就是说,如果你的程序可扩展性不好,一定是程序作者对“单元”的定义不够准确,即单元的概念 之间不够“正交”。而这种架构终是徒有其形,根基不稳。
因此,变量和类的命名才是真正考验架构功力的关键(命名是否准确清晰、单元之间是否有概念重叠或盲区),而和所谓“组合”、“继承”、“桥接”等模式化的“外表”无本质联系。
【伪架构】
实际情况是,程序员早早的就想让自己和“架构”扯上关系,并自封xx架构师。在项目中应用各种模式分层、解耦方法,每个项目都可以产出一套看上 去很复杂的“架构图”,感觉很牛逼的样子,没错,实践这些方法论总不是坏事,但世界观才是方法论的基础,只有在概念上对产品模块有科学的定义,方法论便自 然形成了,《编程珠玑》中一再提及数据结构就是静态的算法,在Web前端领域亦是如此,在页面的建模过程中,定义分解维度要比分解方法更加基础和重要。我 想阿当可以在《Web前端开发修炼之道》的第二版里加上这部分内容。
真正的高手用记事本就能写出高质量的代码、用cvs就能做到完美的版本控制、用字典式的分解就能做好系统架构,我想,这正是剑宗一派的最高境界吧。
第五日:寻找突破
【动心忍性】
技术流派看上去是如此吸引人,高手就像侠客一般,来去如风潇洒自如。但反观自己怎么看怎么没有侠客那股范儿。尽管上文提到了一些道理,了解这些 尽管不是坏事,但缺少实践总感觉是纸上谈兵。更何况,日常的工作又是枯燥无味、繁杂单调。每个人都盼望更高的目标、接触新鲜技术、将新技术运用到日常,在 探索尝试之中寻找成就感。这种感觉可以理解,但却缺少更深层次的思考。因为越到最后越会发现一线的工作才是最有挑战的。当然,我说这话的前提是,你能如前 文所说具备合格的软技能,需要一些技巧让工作变得工整有序、节奏健康,这样你才能将注意力放在纯粹的代码中,摆脱了外界的烦扰,方能从技术的角度思考突 破。这也是从初级到高级的进化过程需要大量的历练的原因。正如玉伯所说,“枯燥是创新的源泉。如果你发现自己没什么新想法,做事缺少激情,很可能是因为你 还未曾体验过真正的枯燥的工作”。
关于如何寻找突破,我的建议是马上动手做、不要等,相信自己的直觉(这里和上文提到的先思后行是两码事)。比如,Slide幻灯控件理应支持触 屏事件以更好的适应移动终端,或许你在用的Slide幻灯版本很旧、或者时间不允许、再或者你害怕对Slide改造而引入bug,不要担心,大不了多花业 余时间,只要想,只要感觉合理和必要,就去做。因为这个过程带来的编程体验才是工程师们独有的美妙体味。我现在还时常深夜写代码,没有打扰、思如泉涌、代 码也更加工整严谨,不失为一种享受。因此,用眼睛去观察,用心去感触,“所以动心忍性,才会增益其所不能”啊。
【得与失】
互联网的发展的确太快,Web前端技术也在花样翻新,有人经不起诱惑,开始做新的尝试。前端技术虽然范围广,但各个分支都还比较容易入门,比如 服务器端脚本编程、再比如纯粹的WebApp,我认为这两者都是前端技术的范畴,毕竟他们都没有脱离“浏览器”,或者说类似浏览器的环境。NodeJS依 赖于V8,WebApp更是软件化的WebPage。只要打好基础,这些方向都是值得深入钻研的,因为,互联网的形态越发多元,新的技术总能找到用武之 地,这就要凭借自己的技术嗅觉和产品直觉,寻找技术和业务的契合点。
这看上去是一种放弃,放弃了自己赖以生存的铁饭碗(熟练的切页面至少不会失业),实则不然。这种想法是一种误区,新的选择并不会让你放弃什么, 就像学会了开车,并不意味着就不会骑车了。其实改变的是思维方式而已,是一种进步,如果你能想通这一点,你也能跟得上互联网发展的脚步了,打开你的思维, 让技术变成你的金刚钻,而不是包袱。
所以,所谓得失之间的权衡,其实就是“解放思想”。做到了这一点,那么你已经在做“技术驱动”了。
【误区】
但是,不要高兴的太早,“技术驱动”是需要大量的积累和经验的。在入行初期,很多人过于着迷与此,从而陷入了迷途。比如有人纠结于是否将dt、 dd的样式清除从reset.css中拿掉,原因是觉得这两个标签的清除样式会耗费一些渲染性能;或者是否需要将for循环改为while循环以提高js 执行速度。尽管这些考虑看上去是合理的,但并不是性能的瓶颈所在,也就是说,你花了很大力气重构的代码带来的页面性能提升,往往还不如将两个css文件合 成一个带来的提升明显。就好比用一把米尺量东西,没必要精确到小数点后10位,因为精确到小数点后2位就已经是不准确的了。这种技术误区常常让人捡了芝麻 丢了西瓜。
话说回来,这里提到的怀疑权威的精神是绝对应当鼓励的,但不应当止于表象,如果怀疑dt的清除样式会对性能带来影响,就应当想办法拿到数据,用事实来证明自己的猜测。数据是不会骗人的。而求证过程本身就是一种能力的锻炼。
【技术驱动】
说到这里,你大概对“技术驱动”有那么一点点感觉了。身边太多人在抱怨“公司不重视前端”、公司不是技术驱动的、技术没机会推动产品业绩、我的价值得不到体现?
什么是技术驱动?简单讲,就是技术对业务有积极推动作用。更多的是工程师发起、工程师影响、工程师负责。刚才提到的用数据说话只是一种“驱动”技巧,那么我需要何种数据,数据从哪里来?我来分享一个实际的场景吧。
工程师A被委派一个重要的频道首页,因为是新年版,所以要赶在年前上线。A学了一点点响应式设计,想在这次重构中加上,但谁也没做过响应式设 计,需求方根本不懂,设计师也懵懵懂懂,交互设计师太忙,做完交互稿就忙别的去了。A纠结了,按部就班的把项目做完上线发布,尽管不会出什么问题,但总觉 少点什么。这时A做了两个决定,1,我要按时完成项目,2,趁机实践我在响应式设计中的想法和思考,若成功,作为附加值赠送给需求方,若失败,权当技术玩 具耍一耍罢了。所以A熟练的提前完成了项目,剩下的时间开始考虑如何将首页适应到各个平台中,视觉设计是一大难题,他用吃饭的时间找了设计师收集建议,对 窄屏中的内容模块做了看似合理的编排,代码上hack一下,能够正确适配,就发布上线了。这件事情需求方不知道,视觉设计师也不了解,交互设计师更没工夫 操心。A感觉挺爽,开始给工程师弟兄们到处炫耀这个好玩的功能,B看了问,手机端访问量如何,A觉得这个问题有道理,就去部署埋点,一周后拿到数据出奇的 意外,首先,移动段的访问量稳步增加,趋势健康,再者,移动端首屏焦点广告位的点击率较PC端高了近一倍,这个数据让A喜出望外,兴奋的拿着报表找到交互 设计师C和市场研究的同事D,D看了报表之后立即启动一个项目,专门调研公司全站响应式设计页面在PC端和移动端的点击率、PV、UV趋势方面的影响…… 后来发生的事情就都水到渠成了,设计师C开始注意设计页面交互时(至少是有条件的考虑)对移动端的适配,D的调研报告也放到了UED老大的案头……接下来 的事情,你懂得。A被指派要出一套响应式最佳实践和规范,最终,A走在了技术的前沿,也因此拿到了好绩效。
这件事情就是一个典型的技术驱动的例子。谁不让你玩技术了,谁不重视你了,谁把你当工具了,谁觉得你的代码没价值?这世界只有自己把自己看扁,谁想跟你这个蝇头小卒过不去?用实力说话,用数据说话,用独到的见解说话,想不做技术驱动都难。
第六日:码农的宿命
【青春饭】
“码农”是IT从业者一个自嘲的称号,也有从事没有发展前景的软件开发职位,靠写代码为生的意思。但我认为码农是一个爱称,编码的农民,和农民 一样有着执着纯真朴实豪爽的共性,仅仅分工不同而已。就好比农业社会对粮食的依赖,工业化进程对计算机应用也有着很强的依赖,大量的需求催生出这样一群 人。他们有智慧的大脑,对于编程,设计,开发都有着熟练的技巧,但多数人看来,码农的特点是:
1,收入低
2,工作单调
3,工作时间长
实际上这个描述非常片面,或者说是外行看热闹。第一,全行业比较来看,软件开发领域收入为中等偏上;第二,程序员一般都是有癖好的,沉浸在自己 的癖好中是不会感觉单调的;第三,程序员有一定的时间自由度(如果你是一名合格的程序员的话),至少不会像流水生产线工人一样。其实,通过几十年的发展, 我们对程序员的定义更加科学,比如很多IT企业都开始建立详细的JM(Job Module),即职级模型,程序员沿着专业方向可以走到很高,甚至可以 说,程序员是可以被当成一生的事业的。
然而,有一个非常普遍的观点是,程序员和做模特一样是吃青春饭的,到了三十岁就要考虑转行或者转管理。尽管这种观点颇具欺骗性,但至少它对一种 人是适用的,即入错了行的人。如果你骨子里不想写程序,就算年纪轻轻为了生计写几年代码,之后肯定会另有他途。心非所属则不必勉强,但问题是,即便如此, 你知道你的心之所属吗?
我们知道,一个成熟的产业一定需要各色岗位来支撑,若要成熟,则需要时间的沉淀,比如实体经济制造业,创意、生产线、高级技工、技术管理四个方 面都产出大量的高级人才。因为历史悠久,我们能看得到。而软件产业则不然,九成以上是刚出道的新手,并没有太多“高级”和“资深”的具体样板可供参照,在 前端开发领域中情况更甚,绝大部分人根本搞不清楚什么样才是“资深”前端工程师,相比传统软件行业近四十年的进化,我不相信仅有几年光景的前端技术岗位能 产出多少货真价实的“资深”。但互联网崛起速度太快,还没有等技术基础打牢,互联网形态就又花样翻新了,这种变化是一种常态,而岗位的设定也在这种变化之 中自然的优胜劣汰,比如两年前可能还难以想象数据部门会需要前端工程师,他们甚至不直接和浏览器打交道。前端工程师需要适应这种变化带来的观念冲击,不要 以为自己只能做切页面、或者只会给页面搞重构、只会搞兼容性,要把自己放在整个软件行业来看。
所以,由于历史“不悠久”导致的岗位模糊本身不是什么大问题,岗位的演化本身就包含在互联网的发展轨迹之中。所以,当今的互联网IT状况,就好 比移动终端的大哥大时代、云计算的肉鸡时代、或者桌面操作系统的DOS时代。因此,前端工程师当前要务是要想清楚看清楚,在互联网中我能做什么,而不是作 为前端工程师我能做什么,所以,从这个角度讲,技术是一个工具,放大来看,技术也只是你职业生涯中很小的组成部分,而你的从业积累、和知识面的广度深度才 是你随着时间的推移慢慢步入“资深”的原因所在,而不是写了个什么框架就变“资深”了。如果有一天互联网形态固定了,它的岗位可能真正就定型了,才会有真 正清晰的职能边界,就像蓝色巨人IBM中的各色岗位一样,边界清晰,权责分明,普通程序员只能实现接口而无机会设计接口、低层级的工程师也无机会跃进式的 接触项目架构、技术经理人也不能轻易对产品有决策性影响,到这时,人的能力才真正的被限制在方圆之内,容不得越界,这种环境下人的成长非常缓慢。根本不会 有像今天互联网乱局之中所提倡的创新、革命、成长和思想解放。简单讲,一旦产业定型,就不太需要很多“创造”了,更多的是“维护”。所以,我个人宁愿互联 网IT“黑暗”的中世纪越久越好,至少对于年轻气盛程序员来说,黑暗的丛林环境才是真正的自然进化最理想的土壤,这时我想起了狄更斯在“双城记”中的开 篇。
“这是最好的时代,这是最坏的时代;这是智慧的时代,这是愚蠢的时代;这是信仰的时期,这是怀疑的时期;这是光明的季节,这是黑暗的季节;这是希望之春,这是失望之冬;人们面前有着各样事物,人们面前一无所有;人们正在直登天堂,人们正在直下地狱”。
【半路出家的危与机】
然而,不管怎样,信心的树立不是一蹴而就的,对于转行做前端的人来说更是如此。俗话说,隔行入隔山。每个行业自有其道,自然不是想做就做。前端 技术领域半路出家者非常多,我们来分析一下转行的心理。第一,看到前端技术入门简单、互联网对前端技术的需求缺口巨大;第二,前端技术所见即所得、感觉学 习起来很快;第三,我身边的某某转行作前端看上去不错、我似乎也可以;第四,我不喜欢我现在做的工作、想换行业、正好前端技术上手较快,就选他吧;第五, 我真的喜欢做Web前端,为它付出再多都是值得的。
转行者的心态比较容易走两个极端,一是只看到新行业的好,二是只觉得原工作很糟糕。但不管是什么行业的转行,对自己的职业规划的思考都应当先行一步。即务必首先清晰的回答这些问题:
1,我能做什么?
2,我不能做什么?
3,我的优势是什么?
4,我的劣势是什么?
5,做新行业对我有何好处?
6,换行会让我付出何种代价?
7,如何定义转行成功?
因为面试的时候一定会被这些问题所挑战。如果支支吾吾说不清楚,要么是对自己未来不负责任,要么骨子里就是草根一族,习惯做什么都蜻蜓点水浅尝 辄止,也难让人信服你的转行是一个权衡再三看起来合理的选择。我无法帮每个人回答这些问题,但至少有两点是确定的,第一,Web前端技术是一个朝阳行业, 绝对值得义无反顾的坚持下去;第二,你将经历从未有过的枯燥、苛刻的历练,所谓痛苦的“行弗乱其所为“阶段。不过话说回来,经历过高考的人,还怕个屁啊。
有心之人自有城府、懂得放弃,看得清大势中的危机、识得懂繁华里的机遇。尤其当立足于Web前端技术时,这种感觉就愈发强烈。因为国内外前端技 术领域从2000年至今一直非常活跃,前端技术前进的步伐也很快,对于一些人来说,不管你是在大公司供职还是创业,不管你是在接外包项目还是自己写开源项 目,从转行到跟得上新技术的脚步是有一些方法和“捷径”的。
第一,梳理知识架构
我们知道知识积累有两种思路,第一种是先构建知识面、建立技术体系的大局观,即构建树干,然后分别深入每一个知识点,即构建枝叶,最终形成大 树。第二种是先收集知识点,越多越好,最后用一根线索将这些知识点串接起来,同样形成大树。第一种方法比较适合科班秀才,第二种方法则更适合转行作前端的 人,即实践先行,理论升华在后。比如对“IE6怪异模式“这条线索来说,要首先将遇到的IE6下的样式bug收集起来,每个bug都力争写一个简单的 demo复现之,等到你收集到第100个bug的时候,再笨的人都能看出一些规律,这时就会自然的理解IE的hasLayout、BFC和各种bug的原 因、你就成为了IE6的hack专家了,当你成为100个知识线索的专家的时候,你已经可以称得上“资深”的水平了。我们知道,10个人中有9个是坚持不 下来的,他们会以项目忙等各种理由万般推托,将自己硬生生的限制在草根一族,坐等被淘汰。所以,对于立志作前端的人来说,这种点滴积累和梳理知识非常重 要。
第二,分解目标
将手头的工作分解为几部分来看待,1,基本技能,2,项目经验,3,沟通能力,4,主动性和影响力。想清楚做一件事情你想在哪方面得到历练,比 如,我之前在做第一次淘宝彩票常规性重构的时候(正好是一次视觉和交互上的全新设计),我清楚的明白这次重构的目的是锻炼自己在架构准富应用时的模块解偶 能力,寻找在其他项目中架构的共通之处,所以我宁愿加班或花更多精力做这个事情,当然更没打算向业务方多解释什么,这件事情对我来说纯粹是技能的锻炼。而 经过这一次重构之后,我意外的发现对业务的理解更透彻深入、更清晰的把握用户体验上的瓶颈所在。如果一开始就把这次常规改版当成一个普通的项目按部就班的 做,我只能说,你也能按时完成项目,按时发布,但真真浪费了一次宝贵的锻炼机会,项目总结时也难有“动心忍性”的体会。
所以,每个项目的每个事情都应当认真对待,甚至要超出认真的对待,想清楚做好每件事对于自己哪方面有所提升?哪怕是一个bug的解决,即便不是 自己的问题也不要草草踢出去了事,而是分析出问题原因,给出方案,有目的involve各方知晓……,正规的对待每个不起眼的小事,时间久了历练了心智, 这时如果突然遇到一个p0级的严重线上bug(比如淘宝首页白屏,够严重的了吧)也不会立即乱了方寸,这也是我上文提到的心有城府自然淡定万倍,而这种淡 定的气场对身边浮躁的人来说也是一种震慑和疗伤,影响力自然而然就形成了。
第三,作分享
做分享这事儿真的是一本万利。有心的人一定要逼着自己做分享,而且要做好。首先,自己了解的知识不叫掌握,只有理解并表达出来能让别人理解才叫 掌握,比如如果你解释不清楚hasLayout,多半说明自己没理解,如果你搞不懂双飞翼的使用场景,可能真的不知道布局的核心要素。再者,作分享绝对锻 炼知识点的提炼能力和表达能力,我们作为工程师不知道多少次和强硬的需求方pk,被击败的一塌糊涂。也反映出工程师很难提炼出通俗易懂的语言将技术要点表 述清楚。而做ppt和分享正是锻炼这种能力,将自己的观点提炼出要点和线索,分享次数多了,自然熟能生巧。档次也再慢慢提高。另一方面,逼迫自己站在公众 场合里大声讲话,本来就是提高自信的一种锻炼。
这时,你或许会问,我讲的东西大家都明白,我讲的是不是多余,我第一次讲讲不好怎么办,大家会不会像看玩猴似的看我“这SB,讲这么烂还上来讲”?要是讲不好我以后再讲没人听怎么办,我今后怎么做人啊?
老实说,这是一道坎,任何人都要跨过去的,谁都一样,你敢鼓起勇气在大庭广众之下向爱人表白,就没勇气对自己的职业宿命说不?其实勇敢的跨越这 一步,你会意外的收获他人的掌声和赞许,这些掌声和赞许不是送给你所分享的内容,而是送给你的认真和勇气。这个心结过不去,那就老老实实呆在自己的象牙塔 里遗老终生,当一辈子工程师里的钻石王老五吧。
【匠人多福】
如果你能耐心读到这里,心里一定有一个疑问,上面说的都是技术上能力上怎样怎样,那我所做项目不给力又当如何?如果项目不挣钱、黄了、裁了,我的努力不就白费了吗?我又有什么绩效和价值呢?
没错,有这种想法的人不在少数。特别是刚出道的校招同学往往更加心高气傲,以为自己有改变世界的本事,一定要参与一个牛逼的团队做一款光鲜靓丽受人追捧能给自己脸上贴金的项目。如果你有这种想法,趁早打消掉这个念头,当然,我们这里先不讨论创业的情形。
第一,如果你刚毕业就加入一个牛逼团队,说难听点,你就是团队中其他人眼中的“猪一样的队友”,不创造价值且拖项目后腿(显然大家都要照顾你的成长啊),按照271理论,你没有理由不是这个1。至少相当长一段时间内是这样。
第二,你在所谓牛逼团队中的创造性受限,因为创新多来自于团队中的“资深“和大牛们,你参与讨论但观点通常不会被采纳,他们只会给你这个菜鸟分活干,想想看,你如何能花两到三年就超越身边的大牛们?甚至连拉近与他们的距离都难。
第三,如果身在牛逼团队,自然心理对周围的牛人们有所期待,希望他们能灌输给你一些牛逼的知识和牛逼的理念。这种思想上的惰性在职场生涯之初是非常危险的。要知道技术和知识本身是很简单和淳朴的,只不过披上了一个光鲜项目的外衣而让人感觉与众不同。
第四,由简入奢易,由奢入简难,做过一个看似光彩的项目,心理再难放平稳,去踏实的做一个看上去不那么酷的产品。这种浮躁心态会严重影响今后的职业发展和成长。
第五,光鲜靓丽的项目被各种老大关注,是难容忍犯错误的,傻瓜都知道犯错误在成长之初的重要性。
就我所看到的情形看,一开始加入看似很牛的项目组,三年后得到的成长,比那些开始加入一个不被重视的项目的同学要小很多,而后者在能力上的弹性 却更大。所以,道理很简单,你是要把一个很酷的项目做的和之前差不多酷,还是把一个不酷的项目做的很酷?项目是不是因为你的加入而变得与众不同了?
从这个角度讲,不管是转行的新人还是刚出道的秀才,最好将自己当作“匠人”来对待,你的工作是“打磨”你的项目,并在这个过程中收获经验和成 长。付出的是勤奋,锻炼的是手艺,磨练的是心智。因此,你的价值来自于你“活儿“的质量,“活儿”的质量来自于你接手的项目之前和之后的差别。做好活儿是 匠人应有的职业心态。想通这一点,内心自然少一些纠结,才会对自己对项目的贡献度有客观的认识,不会感觉被项目所绑架。
做一名多福的匠人,拥有了金刚钻、就不怕揽不到瓷器活儿。但对于人的成长来说,如果说“项目”重要但不关键,那么什么才是关键呢?这个话题还会在接下来的“伯乐与千里马”这篇中给出答案。
【若干年后】
现在,让我们回过头回答一下“青春饭”的问题。在“青春饭”小节中提到,“程序员到三十岁之后需要转行或者转管理吗?”
上文提到,工业化生产的四个领域,1,创意,2,生产线,3,高级技工,4,技术管理。Web前端技术也是如此,可以在这四个领域找到各自的归宿。
第一,“创意“
即和产品需求越走越近,拥有良好的产品感,对产品需求、设计交互把握准确,能够用适当的技术方案推动产品用户体验,属于“架构师”的范畴,因为 职能更加靠前,偏“出主意”型的。这种人更贴近用户,需要活跃的思维、广阔眼界、厚实的项目经验。更多的影响产品体验方面的决策。
第二,“生产线“
即前端基础设施建设,优化前端开发流程,开发工具,包括开发环境、打包上线自动化、和各种监控平台和数据收集等,属于“技术支持”的范畴,相比于很多企业粗犷难用的平台工具,前端技术方面的基础设施建设基础还需更加夯实,因为这是高效生产的基本保证。
第三,“高级技工“
即高级前端开发工程师,专职做项目,将产品做精做透,用代码将产品用户体验推向极致,偏“实战”型的,是项目的中坚力量,直接产出成果,影响产品效益。属于项目里的“资深”。
第四,“技术管理“
即做技术经理,这才是多数人所理解的“管理”,其实就是带团队、靠团队拿成果。这类人具有敏感的技术情结,在技术风潮中把握方向,能够指导培训新人,为各个业务输出前端人才,偏“教练”型的,促进新技术对业务的影响。并有意识的开辟新的技术领域。
可见,转管理可不是想当然,也不是所谓做项目变资深了就能转管理,转了也不一定能做好。根据“彼得原理”,即人总是倾向于晋升到他所不能胜任的岗位,这时就又陷入“帕金森”定律所隐喻的恶性循环之中,直到你带的团队整个垮掉。
所以,转管理应当是一件非常慎重的事情,不是所谓程序员混不下去就转管理这么简单。但不管怎样,有一件事情是需要尤其要想清楚,即,转了管理,技术就丢了吗?我们在第七日“伯乐与千里马”中再深入聊聊这个事儿。
第七日,伯乐与千里马
【师兄们的抉择 1】
千里马常有,而伯乐不常有。——韩愈,“马说”。
一个人这辈子能遇到一个好师兄是一种缘分,可遇不可求。很多人工作中的幸福感似乎也源自这种被认同,被师兄的了解和认同,有人能直言不讳的指出 你的不足,帮你发现机会,并将最适合你做的事情分配给你,这是莫大的幸运,但如此幸运的人十之一二,大多数人因为缺少伯乐的提点,渐渐辱于“奴隶人之手 “,潜力渐失,毁于中庸。
在前端技术领域,这种情况很普遍也很特殊,当然有很多客观原因。即前端技术进入公众视野时间不长,有实力的伯乐更加是凤毛麟角。更何况,Web 前端技术还有着一些江湖气,知识点过于琐碎,技术价值观的博弈也难分伯仲,即全局的系统的知识结构并未成体系,这些因素也客观上影响了“正统“前端技术的 沉淀,奇技淫巧被滥用,前端技术知识的传承也过于泛泛,新人很难看清时局把握主次,加之业务上的压力,未免过早导致技术动作变形。而这些问题也无法全赖自 己全盘消化,若有人指点迷津,情况要好上万倍。因此,前端技术领域,为自己觅得一个靠谱的师兄,重要性要盖过项目、团队、公司、甚至薪水。
这也是上文所说的“项目不重要,师兄才重要“的原因。说到这里就有一个问题,每个人都问下自己,你是想当师弟呢还是想当师兄呢?当师兄有什么好处呢?
没错,很多师兄都是被师兄,甚至没有做好当师兄的准备,更进一步说,不少经理人也都是“被经理人“,没有做好准备就被推到了管理岗位。带人是耗 精力的,师兄要做很多思想斗争才舍得把这些宝贵的精力放在那些菜鸟身上,这不是一个技术问题,而是一个道德问题。要记住,没有谁应该无缘无故把自己所掌握 技能给你倾囊相授,如此皆命也。读到这里,作为菜鸟,作为学徒,作为新人,作为师弟,你做到对这份命运的足够尊重了吗?
尊师重教的传统美德并没有在技术领域得以很好的延续。也正因为此,人才梯队难建立起来,但对于师兄来说,却是有更多机遇的。
【师兄们的抉择 2】
作为师兄,不管是主动还是被动,肯定会想当师兄对我有什么提升?对于初次做师兄的人来说,最大的提升在于两方面,1,任务分解,2,问题分析。
第一,任务分解,作为师兄要给师弟派分任务,就涉及到任务分解,分解这事儿往低了说,就是派活,往高了说,其实就是做“架构”,比如一个页面, 按照什么思路进行模块划分,模块划分是否适合单人开发,如何控制共用样式和共用脚本,我需要为他提供什么接口,如何控制他的代码并入整个页面时不会影响整 体页面代码的熵值,这些都是实打实的“架构“应该包含的问题,而从小页面开始就做这种锻炼,做的多了,“架构感”自然就形成了。
第二,问题分析,在之前自己写代码都是单打独斗,什么都是用代码解决问题,但一旦涉及协作,就要强迫自己分析问题,或者说给徒弟分析问题,告诉 他应当用什么方法来解决问题,当说到“方法”时,脑子里定形成了一个方案,按照这个方案路子走一定能解决问题。分析问题比写代码要更抽象、更高效,因为在 脑子里构建方案要比写代码要快,思考也会更加缜密,当锻炼的多了,思考越来越快,代码的草稿也很快就在脑海中形成了,这也是我们说为什么很多人不写代码但 编码思路和水平都很高的原因。
这些工作方法对了,积累多了,就是提高。对于技术经理人来说,也是同样的道理。所以,就像在第五日的“得与失”部分提到的那样,转身师兄、变身管理并不意味着“失“掉技术饭碗,而是一种进步。
【做自己的伯乐】
那么,在前端技术领域里什么样的人才算千里马,其实人人都是千里马,人人都可以发掘自己的潜力,如果上面的文字你能读懂,能认可,这种自我发掘已经开始了,没有一个好伯乐又何妨呢?做一个勤快的小码农,少一些势利的纷争,很快会发现,自己才是最好的伯乐。
但这并不是说,他人对自己的观点不重要,有时甚至要综合各种声音,所以,多找身边的大牛们聊聊天,多找你的师兄和主管,不管他们给你的建议是多么形而上,总有一些声音对你是有益的,多收集,有好处。
第八日,做地球上最牛的UED
【谁推动了历史前进,英雄?还是人民?】
“做地球上最牛的UED!”,这是淘宝UED创立之初的口号,现在被渐渐淡忘了,因为微博上的一些讨论,又想起了这份曾经美好的初衷。玉伯也感 叹道:“这愿景曾吸引了多少好汉前往投奔呀。只可惜短短几年间,这愿景好像越来越远了”。问题是,要做好一个团队,靠的是个人、还是整体?愿景是越来越远 了吗?
是谁推动了历史的前进,是英雄?还是人民?微观来看,是英雄,宏观来看,是人民。再放大了看,是互联网大潮之崛起推动了前端技术的进步,时势需要UED、需要用户体验。
所以,UED团队的创立发展受这些积极的外因影响,赶上了好时候,成员也跟着沾光。然而,我并不关心这个口号,我只关心体制内的关键人物,那些 带动整个团队水涨船高的人们。往往我们发现,某些人的高度代表了整个团队的高度,个体的影响力代表了整个团队的影响力,某个人的水平代表了整个团队的水 平。支付宝、淘宝、腾讯、百度、盛大,都是如此。而我们作为普通的个体,正是要励志成为这种人,成为真真用技术推动用户体验前进的尖刀人物。
这时我想起了很多人在知乎上的问题,关于跳槽、关于转行、关于创业、关于各种UED团队。我想,读得懂我上面的文字,你心理也许会有自己的答案。
【归宿】
最后,还有一个不得不说的问题,即归属问题,前端开发应当归属于UED还是技术部门?应当说,当前Web前端技术的价值体现在“用户体验“上。 是用户体验这块阵地最后一道坎。也就是说,前端工程师应当重点考虑我所作的页面的感官体验。这是需要一些灵感和感性的,应当看到帅气优雅的界面会心有所 动、或者实现一款精巧的小组件时萌生一阵快意。这种所见即所得的美妙编程体验正是其他后端工程师无法体验到的。因此,这种精确到像素级的精工雕琢虽然不直 接决定产品生死,但却是提升产品品味和时尚感的要素。物质越来越丰富的今天,大众的更高诉求不就是品味和时尚吗?
如果将前端归到技术部门,一方面和“设计“离的更远,代码写的规规矩矩但渐缺少了灵性,另一方面作为工程师又缺少计算机专业课的功底,才真正丧 失了优势所在,如果有一天,前端工程师的平均水平足够高,清一色的计算机科班出身,似乎更合适归入到技术部门。所以,Web前端工程师是“工程师“,需要 科学严谨的编程能力,但身处UED所应当具备的美感和灵性是万不可被剥夺去的。
还有一点,Web前端工程师作为UED之中最具实践精神和逻辑思维的工种,是能够将技术对设计的影响发挥到最大,可以催生出大量的创造和革新的,这一点也是传统后端工程师所不具备的。
第九日,前端技术体系
现在越来越感觉到前端技术需要成体系的积累,一方面可以规范我们的前端技术培训,另一方面,作为知识线索为新人做指引,省的走弯路,避免陷入奇技淫巧的深坑之中不能自拔。
之前我整理了一下“前端技术知识结构”,罗列的比较散,但也基本表述清楚了我的观点。今年上半年也在整个研发中心组织了一次前端技术培训,对于前端技术的演化规律也有过整理,都放在了这个ppt中,希望对大家有所帮助。
【一】 面向对象的基本概念 面向对象的英文全称叫做Object Oriented,简称OO。OO其实包括OOA(Object Oriented Analysis,面向对象分析)、OOD(Object Oriented Design,面向对象设计)和OOP(Object Oriented Programming,面向对象的程序设计)。
通常所说的面向对象是指OOP, OOP是一种围绕真实世界的概念来组织模型的程序设计方法,它采用对象来描述问题空间的实体。在使用计算机解决问题时,对象是作为计算机模拟真实世界的一个抽象,一个对象就是一个物理实体或逻辑实体,它反映了系统为之保存信息和(或)与它交互的能力。使其具有自己的属性和行为, 从而简化对复杂事物的描述,更有利于工程的可维护性和扩展性。
OOP同结构化程序设计相比最大的区别就在于: 前者首先关心的是所要处理的数据,而后者首先关心的是功能。
【二】 面向对象三个基本特征
封装 (Encapsulation) 将数据以及相关的操作组织在一起,成为独立的构件。外部无法直接访问这些封装了的数据,从而保证了这些数据的正确性。封装的目的是为了内部数据表现形式和实现细节的隐藏,信息隐藏是为了减少系统各部分间的依赖性,各部分间必须通过明确的通道传送信息,也就是对象间的接口.这样一来,隐藏了部分内部的细节,极大方便系统的开发,维护和扩展。
继承 (Inheritance) 继承是一种联结类的层次模型,并且允许和鼓励类的重用,它提供了一种明确表述共性的方法。一个新类可以从现有的类中派生,这个过程称为类的继承。新类继承了原始类的特性,新类称为原始类的派生类(子类),而原始类称为新类的基类(父类)。派生类可以从它的基类那里继承方法和实例变量,并且派生类可以修改或增加新的方法使之更适合特殊的需求。继承性很好地解决了软件的可重用性问题。
多态 (Polymorphism) 多态是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单的说,就是允许类与类之间相同方法名的指针得以调用, 这样很好地解决了应用程序函数同名问题。实现多态,有二种方式,覆盖,重载。
【三】 Javascript 面向对象
javascript本身是一种基于对象(object-based)的语言,我们日常编码过程中用到的所有东西几乎都是对象(Number, String, Boolean, etc.)。但是,相对于一些流行的面向对象语言(C++, C#, java),它又不是一种真正的面向对象编程(OOP)语言,因为它的语法中没有class的概念。
Keyword: class, object, `this`, closure, constructor, prototype
几种对象封装的方法
之一、几种对象封装的方法
1. 对象封装 – 原始模式
假定我们把猫看成一个对象,它有”name”和”color”两个属性, “etc” 行为。
var Cat = { name: '' color: '', eat: function() {} };
现在,我们需要根据这个原型对象的规格(schema),生成两个实例对象。
function eat() { console.log('I\'m eta fish'); } var cat1 = {name: 'Kitty', color: 'white', eat: eat}; var cat2 = {name: 'Smokey', color: 'black', eat: eat}; // var cat3, cat4 ,...
不方便创建多个实例对象,扩展性差, 实例(cat1, cat2)之间找不到联系。…
2. 对象封装 – 构造函数模式
“构造函数”,就是一个普通函数,但是内部使用了 `this` 变量。对函数使用 `new` 运算符,就能生成实例,并且 `this` 变量会绑定在实例对象上。
使用构造器创建出来的对象会有一个 `constructor` 属性,指向它们的构造函数。
`Class` 只是一个模板,创建出来的来实例都是由模板生成。
比如,猫的原型对象现在可以这样写:
function Cat(name,color){ this.name = name; this.color = color; this.eat = function() { console.log('eat fish'); }; } var cat1 = new Cat('Kitty', 'black'); console.log(cat1.name); // Kitty console.log(cat1 instanceof Cat); // TRUE // 这时 cat1 实例会自动含有一个 `constructor` 属性,指向它们的构造函数 `Cat`。 var cat2 = Cat('Smokey', 'white'); console.log(cat2); // undefined
3. 对象封装 – Prototype 模式
`prototype` 是 `Function` 对象的一个属性,这个属性指向另一个对象。 这个对象的所有属性和方法,都会被构造函数的实例继承。
同时 `prototype` 又存在一个指向构造函数的引用 `constructor`,这样就成功的构成一个循环引用的原型链结构。
我们可以把那些不变的属性和方法,直接定义在 `prototype` 对象上, 节省内存开销。
function Cat(name, color) { this.name = name; this.color = color; } Cat.prototype.type = 'mammal'; Cat.prototype.eat = function() { console.log('eat fish'); }; var cat1 = new Cat('Kitty', 'white'); var cat2 = new Cat('Smokey', 'black'); console.log(cat1.type); // mammal console.log(cat1.eta === cat2.eta); // TRUE, same reference console.log(cat1.constructor === Cat) // TRUE, from Person.prototype
之二、继承 (Inheritance)
将持有共性特点的属性或行为抽象出一个基本类, 可以按不同层次结构的业务分组抽象出多个基础类。
Cat, Bird
1. 继承 – 构造函数绑定
使用call或apply方法,将父对象的构造函数绑定在子对象上。
function Animal() { this.species = 'animal'; this.sleep = function() { console.log('I\'m sleep at night'); }; } function Cat(name, color) { this.name = name; this.color = color; }
让`Cat` 继承 `Animal` 的特性:
/** @class Cat */ function Cat(name, color) { Animal.apply(this); this.name = name; this.color = color; } var cat1 = new Cat('Kitty', 'white'); cat1.sleep(); // I am sleep at night
2. 继承 – 原型链继承
如果”猫”的prototype对象,指向一个Animal的实例,那么所有”猫”的实例,就能继承Animal了。
/** @class Cat */ function Cat(name, color) { this.name = name; this.color = color; } Cat.prototype = new Animal; Cat.prototype.eta = function() { console.log('fish is my delicious'); };
它相当于完全删除了prototype 对象原先的值,然后赋予一个新值
// 任何一个prototype对象都有一个constructor属性,指向它的构造函数 Cat.prototype.constructor = Cat; // fix prototype chains var cat = new Cat('Kitty', 'fish'); cat.eat(); // fish is my delicious cat.sleep(); // I'm sleep at night' console.log(cat instanceof Cat); // TRUE console.log(cat instanceof Animal); // TRUE
需要创建父类实列来实现 `prototype` 继承
3. 继承 (Inheritance) – 利用空对象作为中介实现原型继承
var F = function() {}; F.prototype = Animal.prototype; Cat.prototype = new F(); Cat.prototype.constructor = Cat;
我们将上面的方法,封装成一个函数,便于使用。
function extend(ctor, superctor, px) { if (!superctor || !ctor) throw Error('extend failed, verify dependencies'); var F = function() {}; F.prototype = superctor.prototype; ctor.prototype = new F(); ctor.prototype.constructor = ctor; ctor.superclass = superctor.prototype; // cache super class proto reference. if (px) { // extend class implements for (var k in px) { if (px.hasOwnProperty(k)) ctor.prototype[k] = px[k]; } } return ctor; }
4 继承 – 借住工具方法实现继承
/** @class Mammal */ extend(Cat, Animal, { eat: function() { Cat.superclass.eat.call(this); // call super method console.log('Also i like some ofther food, such as beef and more.'); } }); var cat = new Cat('Smokey', 'fish'); cat.sleep(); cat.eat(); console.log(cat instanceof Animal); console.log(cat instanceof Cat);
之三、多态
1. 多态 – 通过重写原型方法来实现方法重名调用
/** @class Cat */ extend(Cat, Animal, { eat: function() { Cat.superclass.eat.call(this); // call super method console.log('Also i like some ofther food, such as beef and more.'); } });
2. 多态 (Polymorphism) – 原型继承 `prototype` 链上的方法、属性查找
【四】总结 Summary
Constructor
Prototype
Inheritance
/**
* 日期处理工具类
*/
var DateUtil = function(){
/**
* 判断闰年
* @param date Date日期对象
* @return boolean true 或false
*/
this.isLeapYear = function(date){
return (0==date.getYear()%4&&((date.getYear()%100!=0)||(date.getYear()%400==0)));
}
/**
* 日期对象转换为指定格式的字符串
* @param f 日期格式,格式定义如下 yyyy-MM-dd HH:mm:ss
* @param date Date日期对象, 如果缺省,则为当前时间
*
* YYYY/yyyy/YY/yy 表示年份
* MM/M 月份
* W/w 星期
* dd/DD/d/D 日期
* hh/HH/h/H 时间
* mm/m 分钟
* ss/SS/s/S 秒
* @return string 指定格式的时间字符串
*/
this.dateToStr = function(formatStr, date){
formatStr = arguments[0] || "yyyy-MM-dd HH:mm:ss";
date = arguments[1] || new Date();
var str = formatStr;
var Week = ['日','一','二','三','四','五','六'];
str=str.replace(/yyyy|YYYY/,date.getFullYear());
str=str.replace(/yy|YY/,(date.getYear() % 100)>9?(date.getYear() % 100).toString():'0' + (date.getYear() % 100));
str=str.replace(/MM/,date.getMonth()>9?(date.getMonth() + 1):'0' + (date.getMonth() + 1));
str=str.replace(/M/g,date.getMonth());
str=str.replace(/w|W/g,Week[date.getDay()]);
str=str.replace(/dd|DD/,date.getDate()>9?date.getDate().toString():'0' + date.getDate());
str=str.replace(/d|D/g,date.getDate());
str=str.replace(/hh|HH/,date.getHours()>9?date.getHours().toString():'0' + date.getHours());
str=str.replace(/h|H/g,date.getHours());
str=str.replace(/mm/,date.getMinutes()>9?date.getMinutes().toString():'0' + date.getMinutes());
str=str.replace(/m/g,date.getMinutes());
str=str.replace(/ss|SS/,date.getSeconds()>9?date.getSeconds().toString():'0' + date.getSeconds());
str=str.replace(/s|S/g,date.getSeconds());
return str;
}
/**
* 日期计算
* @param strInterval string 可选值 y 年 m月 d日 w星期 ww周 h时 n分 s秒
* @param num int
* @param date Date 日期对象
* @return Date 返回日期对象
*/
this.dateAdd = function(strInterval, num, date){
date = arguments[2] || new Date();
switch (strInterval) {
case 's' :return new Date(date.getTime() + (1000 * num));
case 'n' :return new Date(date.getTime() + (60000 * num));
case 'h' :return new Date(date.getTime() + (3600000 * num));
case 'd' :return new Date(date.getTime() + (86400000 * num));
case 'w' :return new Date(date.getTime() + ((86400000 * 7) * num));
case 'm' :return new Date(date.getFullYear(), (date.getMonth()) + num, date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds());
case 'y' :return new Date((date.getFullYear() + num), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds());
}
}
/**
* 比较日期差 dtEnd 格式为日期型或者有效日期格式字符串
* @param strInterval string 可选值 y 年 m月 d日 w星期 ww周 h时 n分 s秒
* @param dtStart Date 可选值 y 年 m月 d日 w星期 ww周 h时 n分 s秒
* @param dtEnd Date 可选值 y 年 m月 d日 w星期 ww周 h时 n分 s秒
*/
this.dateDiff = function(strInterval, dtStart, dtEnd) {
switch (strInterval) {
case 's' :return parseInt((dtEnd - dtStart) / 1000);
case 'n' :return parseInt((dtEnd - dtStart) / 60000);
case 'h' :return parseInt((dtEnd - dtStart) / 3600000);
case 'd' :return parseInt((dtEnd - dtStart) / 86400000);
case 'w' :return parseInt((dtEnd - dtStart) / (86400000 * 7));
case 'm' :return (dtEnd.getMonth()+1)+((dtEnd.getFullYear()-dtStart.getFullYear())*12) - (dtStart.getMonth()+1);
case 'y' :return dtEnd.getFullYear() - dtStart.getFullYear();
}
}
/**
* 字符串转换为日期对象
* @param date Date 格式为yyyy-MM-dd HH:mm:ss,必须按年月日时分秒的顺序,中间分隔符不限制
*/
this.strToDate = function(dateStr){
var data = dateStr;
var reCat = /(\d{1,4})/gm;
var t = data.match(reCat);
t[1] = t[1] - 1;
eval('var d = new Date('+t.join(',')+');');
return d;
}
/**
* 把指定格式的字符串转换为日期对象yyyy-MM-dd HH:mm:ss
*
*/
this.strFormatToDate = function(formatStr, dateStr){
var year = 0;
var start = -1;
var len = dateStr.length;
if((start = formatStr.indexOf('yyyy')) > -1 && start < len){
year = dateStr.substr(start, 4);
}
var month = 0;
if((start = formatStr.indexOf('MM')) > -1 && start < len){
month = parseInt(dateStr.substr(start, 2)) - 1;
}
var day = 0;
if((start = formatStr.indexOf('dd')) > -1 && start < len){
day = parseInt(dateStr.substr(start, 2));
}
var hour = 0;
if( ((start = formatStr.indexOf('HH')) > -1 || (start = formatStr.indexOf('hh')) > 1) && start < len){
hour = parseInt(dateStr.substr(start, 2));
}
var minute = 0;
if((start = formatStr.indexOf('mm')) > -1 && start < len){
minute = dateStr.substr(start, 2);
}
var second = 0;
if((start = formatStr.indexOf('ss')) > -1 && start < len){
second = dateStr.substr(start, 2);
}
return new Date(year, month, day, hour, minute, second);
}
/**
* 日期对象转换为毫秒数
*/
this.dateToLong = function(date){
return date.getTime();
}
/**
* 毫秒转换为日期对象
* @param dateVal number 日期的毫秒数
*/
this.longToDate = function(dateVal){
return new Date(dateVal);
}
/**
* 判断字符串是否为日期格式
* @param str string 字符串
* @param formatStr string 日期格式, 如下 yyyy-MM-dd
*/
this.isDate = function(str, formatStr){
if (formatStr == null){
formatStr = "yyyyMMdd";
}
var yIndex = formatStr.indexOf("yyyy");
if(yIndex==-1){
return false;
}
var year = str.substring(yIndex,yIndex+4);
var mIndex = formatStr.indexOf("MM");
if(mIndex==-1){
return false;
}
var month = str.substring(mIndex,mIndex+2);
var dIndex = formatStr.indexOf("dd");
if(dIndex==-1){
return false;
}
var day = str.substring(dIndex,dIndex+2);
if(!isNumber(year)||year>"2100" || year< "1900"){
return false;
}
if(!isNumber(month)||month>"12" || month< "01"){
return false;
}
if(day>getMaxDay(year,month) || day< "01"){
return false;
}
return true;
}
this.getMaxDay = function(year,month) {
if(month==4||month==6||month==9||month==11)
return "30";
if(month==2)
if(year%4==0&&year%100!=0 || year%400==0)
return "29";
else
return "28";
return "31";
}
/**
* 变量是否为数字
*/
this.isNumber = function(str)
{
var regExp = /^\d+$/g;
return regExp.test(str);
}
/**
* 把日期分割成数组 [年、月、日、时、分、秒]
*/
this.toArray = function(myDate)
{
myDate = arguments[0] || new Date();
var myArray = Array();
myArray[0] = myDate.getFullYear();
myArray[1] = myDate.getMonth();
myArray[2] = myDate.getDate();
myArray[3] = myDate.getHours();
myArray[4] = myDate.getMinutes();
myArray[5] = myDate.getSeconds();
return myArray;
}
/**
* 取得日期数据信息
* 参数 interval 表示数据类型
* y 年 M月 d日 w星期 ww周 h时 n分 s秒
*/
this.datePart = function(interval, myDate)
{
myDate = arguments[1] || new Date();
var partStr='';
var Week = ['日','一','二','三','四','五','六'];
switch (interval)
{
case 'y' :partStr = myDate.getFullYear();break;
case 'M' :partStr = myDate.getMonth()+1;break;
case 'd' :partStr = myDate.getDate();break;
case 'w' :partStr = Week[myDate.getDay()];break;
case 'ww' :partStr = myDate.WeekNumOfYear();break;
case 'h' :partStr = myDate.getHours();break;
case 'm' :partStr = myDate.getMinutes();break;
case 's' :partStr = myDate.getSeconds();break;
}
return partStr;
}
/**
* 取得当前日期所在月的最大天数
*/
this.maxDayOfDate = function(date)
{
date = arguments[0] || new Date();
date.setDate(1);
date.setMonth(date.getMonth() + 1);
var time = date.getTime() - 24 * 60 * 60 * 1000;
var newDate = new Date(time);
return newDate.getDate();
}
return this;
}();
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8"/>
<script type="text/javascript" src="./DateUtil.js" ></script>
<script type="text/javascript">
var date = new Date();
document.write("penngo test DateUtil.js=====================" + date + "<br/>");
document.write("date========================================" + date + "<br/>");
document.write("isLeapYear==================================" + DateUtil.isLeapYear(date) + "<br/>");
document.write("dateToStr===================================" + DateUtil.dateToStr('yyyy-MM-dd HH:mm:ss', date) + "<br/>");
document.write("dateAdd('d', 2, date)=======================" + DateUtil.dateToStr('yyyy-MM-dd HH:mm:ss', DateUtil.dateAdd('d', 2, date)) + "<br/>");
var date2 = DateUtil.dateAdd('s', 3, date);
document.write("dateDiff('s', date, date2)==================" + DateUtil.dateDiff('s', date, date2) + "<br/>");
document.write("strToDate('2013-01-16 00:27:23')============" + DateUtil.strToDate('2013-01-16 00:27:23') + "<br/>");
document.write("strFormatToDate=============================" + DateUtil.strFormatToDate('yyyy-MM-dd HH:mm:ss', '2013-01-16 00:27:23') + "<br/>");
document.write("dateToLong==================================" + DateUtil.dateToLong(date) + "<br/>");
document.write("longToDate==================================" + DateUtil.longToDate(DateUtil.dateToLong(date)) + "<br/>");
document.write("isDate('2013-01-16 00:27:23', 'yyyy-MM-dd HH:mm:ss')=" + DateUtil.isDate('2013-01-16', 'yyyy-MM-dd') + "<br/>");
document.write("datePart====================================" + DateUtil.datePart('m', date) + "<br/>");
document.write("maxDayOfDate================================" + DateUtil.maxDayOfDate(date) + "<br/>");
</script>
</head>
<body>
</body>
</html>
===========penngo test DateUtil.js==========
date========================================Wed Jan 16 2013 01:14:23 GMT+0800 (中国标准时间)
isLeapYear==================================false
dateToStr===================================2013-01-16 01:14:23
dateAdd('d', 2, date)=======================2013-01-18 01:14:23
dateDiff('s', date, date2)==================3
strToDate('2013-01-16 00:27:23')============Wed Jan 16 2013 00:27:23 GMT+0800 (中国标准时间)
strFormatToDate=============================Wed Jan 16 2013 00:27:23 GMT+0800 (中国标准时间)
dateToLong==================================1358270063903
longToDate==================================Wed Jan 16 2013 01:14:23 GMT+0800 (中国标准时间)
isDate('2013-01-16 00:27:23', 'yyyy-MM-dd HH:mm:ss')=true
datePart====================================14
maxDayOfDate================================31
public class DemoConfig extends JFinalConfig {
//在系统停止时调用的方法
public void beforeJFinalStop() {
};
//在系统启动时调用的方法
@Override
public void afterJFinalStart() {
// TODO Auto-generated method stub
super.afterJFinalStart();
}
}
Interceptors是jfinal aop的实现方式,通过实现Interceptor接口以及使用@Before可以
精确进行配置,
Interceptor接口仅仅定了一个方法void intercept(ActionInvocation ai);
我们可以让一个类实现这个接口,重写方法,如:
public class DemoInterceptor implements Interceptor {
public void intercept(ActionInvocation ai) {
System.out.println("Before action invoking");
ai.invoke();
System.out.println("After action invoking");
}
}
就写好了一个拦截器。
拦截器配置有三个级别,global级,controller级,action级。global级的拦截器将对所有的
action进行拦截,controller级拦截器将对该controller中的所以action拦截,action级拦截器
只对该action进行拦截。
global级拦截器在
public void configInterceptor(Interceptors me) {
me.add(new DemoInterceptor());
}
中配置,controller级拦截器使用@Before放在controller类定以前进行配置,action级拦截器
使用@Before放在action定义前进行配置。具体配置如下:
@Before(DemoInterceptor.class) // 配置一个Controller级别的拦截器
public class HelloController extends Controller {
@Before(AaaInterceptor.class)
public void index() {
renderText("配置一个action级别的拦截器");
}
@Before({AaaInterceptor.class, BbbInterceptor.class})
public void test() {
renderText("配置多个action级别的拦截器");
}
@ClearInterceptor
public void login() {
renderText("清除上一级别(Controller级)的拦截器");
}
@ClearInterceptor(ClearLayer.ALL)
public void clearAllLayers() {
renderText("清除所有级别(Global级与Controller级)的拦截器");
}
}
render系列的方法将渲染不同类型的视图并返回给客户端,jfinal目前支持的视图类型有:freemarker,jsp,velocity,json,file,text,html等等,此外还可以继承render抽象类来无限扩展视图类型。
使用render(String)方法来渲染视图,是请求转发方式渲染视图的,
当执行完一个action后,想重定向到另一个action时,使用redirect(getRequest().getContextPath()+"/user");
getRequest().getContextPath()是工程的名字,
"/user"是想访问的控制类的映射的路由配置。
在使用jfinal开发时,把项目部署到tomcat后,访问会遇到404问题,解决办法是:1.
在jsp的每个访问后台方法的链接都加上工程的名称,如:
<a href="${pageContext.request.contextPath }/user"><b>user管理</b></a>
一些静态资源也要加上工程名称,如css,js,等等。
得到工程路径的方法2:先配置
public void configHandler(Handlers me) {
me.add(new ContextPathHandler("base"));//得到工程路径
}
调用
getAttr("base")
方法就得到工程路径了
在jfinal中的configInterceptor方法中加入的拦截器是全局拦截器,所以的访问都会先经过拦截器,当只有少数类不需要经过拦截器,但是大多数类需要经过拦截器,就配置全局拦截器,在不需要经过拦截器的类中加上@ClearInterceptor (xxx.class)就可以了。
,当拦截器只需要在访问具体的业务才调用时就不要在configInterceptor方法中加入此拦截器,只要在具体的业务控制类的前面加上@Before(BlogInterceptor.class)就可以了。
当只想拦截方法时,就在方法上加上@Before()就可以了
getPara系列方法分为两种类型 。第一种类型为 第一个形参为String 的 getPara系列 方法 。该系列 方法 是对HttpServletRequest.getParameter(String name) 的封装 , 这类方法都是转调了 HttpServletRequest.getParameter(String name)。第二种类型 为第一个形 参为 int 或无形参的 getPara 系列 方法。 该系列方法 是去获取 urlPara 中所带的参数值。 getParaMap与 getParaNames分别对应 HttpServletRequest 的 getParameterMap与 getParameterNames 。
记忆技巧:第一个参数为 String类型的将获取表单或 url中问号挂参的 域值 。第 一个参数为 int或 或无参 数的 urlPara中的参数值 。
setAttr("",value)转调了HttpServletRequest.setAttribute("",value)方法,可以向页面传值
基于JFinal 的web项目需要创建一个 继承自 JFinalConfig类的 子类 ,该类用 于对整个 web项目进行配置 项目进行配置 。
JFinalConfig 子类需要实现 五个抽象方法 ,如:
public class DemoConfig extends JFinalConfig {
public void configConstant(Constants me) {}
public void configRoute(Routes me) {}
public void configPlugin(Plugins me) {}
public void configInterceptor(Interceptors me) {}
public void configHandler(Handlers me) {}
}
configConstant
此方法用来配置 JF inal 常量 值,如开发模式 devMode 的配置,默认 视 图类型 ViewType 的配置 的配置 ,如下 代码 配置了 JFinal 运行在开发模式下且默认视图 类型为 JSP:
public void configConstant(Constants me) {
me.setDevMode(true);
me.setViewType(ViewType.JSP);
}
在开发模式下 ,JFinal会对每次 请求输出报告,如本会对每次 请求输出报告,如本请求的 Controller、 Method 以及请求所携带的参数。 以及请求所携带的参数。JFinal 支持 JSP 、 FreeMarker、Velocity三种常 用视图 。
configRoute
此方法用来配置 JF inal 访问 路由 ,如下 代码 配置了 将 ”/hello” 映射到 HelloController 这个控制器 , 通过以下的配置,http://localhost/hello将访问HelloController.index()方法,而
http://localhost/hello/other将访问到HelloController.other()方法.
字符串与控制类的映射是:
public void configRoute(Routes me) {
me.add("/hello", HelloController.class);
}
Routes 类主要 有如下 两个 方法:
public Routes add(String controllerKey, Class<? extends Controller> controllerClass, String viewPath)
public Routes add(String controllerKey, Class<? extends Controller> controllerClass)
第一个参数 controllerKey是指访问某个 Controller所需要的一个字符串 ,该 字符串唯一对应个 Controller,controllerKey仅能定位到 仅能定位到 Controller。第二个参 数 controll er Class 是该 controllerKey所对应 到的 Controller。第三个参数 view Path 是指 该 Controller返回的视图 的相对路径。当 view Path未指定时默认值为 controllerKey。
1.当url是http://localhost/controllerKey时,调用的是对应控制类的index()方法;
当需要传参数时,url这样写:http://localhost/controllerKey/a-b-c,参数之间用中横线分开,
index()方法中调用getPara(i)得到参数,i是参数对应的下标,例如a的下标是0,b的下标是1,c的下标是2.
2.当url是http://localhost/controllerKey/method时,调用的是对应控制类的method()方法;
3.
JFinal 在以上路由 规则之外 还提供了 ActionKey注解, 可以打破 原有 规则, 以下是代码示例 :
public class HelloController extends Controller{
@ActionKey("second")
public void second(){
System.out.println("0="+getPara(0));
System.out.println("1="+getPara(1));
System.out.println("2="+getPara(2));
renderText("yjw");
}
}
这样url可以写成http://localhost/second/1-2-3,不用写控制类的映射了。
4.
如果以上所有路由规则都不能满足需求,开发者还可根据要使用 Handler定制更加个性化的路由,大体思就是在Handl er 中改变第一个参数 String target的值。
摘要: JFinal主要特点:MVC架构,设计精巧,使用简单 遵循COC原则,零配置,无xml ActiveRecord支持,使数据库开发极致快速 自动加载修改后的java文件,开发过程中无需重启web server AOP支持,拦截器配置灵活,功能强大 Plugin体系结构,扩展性强 多视图支持,支持FreeMarker、JSP、Velocity 强大的Validator后端校验功能 功能齐全,拥有st...
阅读全文
<bean id="bookOutInThread" class="com.ourselec.eam.filter.BookOutInThread" init-method="runThread"/>
先把一个类交给spring管理,在配置初始化调用的方法
摘要: 时下很多 Web 框架 都实现了 Form 表单域与 Java 对象属性的自动装配功能,该功能确实非常有用,试想如果没这功能则势必到处冲积着 request.getParameter() 系列方法与类型转换方法的调用。重复代码量大,容易出错,同时又不美观,影响市容。 现在的问题是,这些框架通过什么方法实现自动装配的?如果不用这些框架我们自己如何去实现呢?尤其对于那些纯 JSP/Servle...
阅读全文
jQuery 是一个 JavaScript 函数库。
jQuery 库包含以下特性:
- HTML 元素选取
- HTML 元素操作
- CSS 操作
- HTML 事件函数
- JavaScript 特效和动画
- HTML DOM 遍历和修改
- AJAX
- Utilities
通过 jQuery,您可以选取(查询,query) HTML 元素,并对它们执行“操作”(actions)。
————————————————————
jQuery 语法
jQuery 语法是为 HTML 元素的选取编制,可以对元素执行某些操作。
基础语法是:$(selector).action()
美元符号定义 jQuery
选择符(selector)“查询”和“查找” HTML 元素
jQuery action() 执行对元素的操作
实例
$(this).hide() - 隐藏当前元素
$("p").hide() - 隐藏所有段落
$("p.test").hide() - 隐藏所有 class="test" 的段落
$("#test").hide() - 隐藏所有 id="test" 的元素
提示:jQuery 使用的语法是 XPath 与 CSS 选择器语法的组合。在本教程接下来的章节,您将学习到更多有关选择器的语法。
选择器允许您对元素组或单个元素进行操作。
————————————————————
jQuery 选择器
在前面的章节中,我们展示了一些有关如何选取 HTML 元素的实例。
关键点是学习 jQuery 选择器是如何准确地选取您希望应用效果的元素。
jQuery 元素选择器和属性选择器允许您通过标签名、属性名或内容对 HTML 元素进行选择。
选择器允许您对 HTML 元素组或单个元素进行操作。
在 HTML DOM 术语中:
选择器允许您对 DOM 元素组或单个 DOM 节点进行操作。
————————————————————
jQuery 元素选择器
jQuery 使用 CSS 选择器来选取 HTML 元素。
- $("p") 选取 <p> 元素。
- $("p.intro") 选取所有 class="intro" 的 <p> 元素。
- $("p#demo") 选取 id="demo" 的第一个 <p> 元素。
————————————————————
jQuery 属性选择器
jQuery 使用 XPath 表达式来选择带有给定属性的元素。
- $("[href]") 选取所有带有 href 属性的元素。
- $("[href='#']") 选取所有带有 href 值等于 "#" 的元素。
- $("[href!='#']") 选取所有带有 href 值不等于 "#" 的元素。
- $("[href$='.jpg']") 选取所有 href 值以 ".jpg" 结尾的元素。
————————————————————
jQuery CSS 选择器
jQuery CSS 选择器可用于改变 HTML 元素的 CSS 属性。
语法 描述
- $(this) 当前 HTML 元素
- $("p") 所有 <p> 元素
- $("p.intro") 所有 class="intro" 的 <p> 元素
- $(".intro") 所有 class="intro" 的元素
- $("#intro") id="intro" 的第一个元素
- $("ul li:first") 每个 <ul> 的第一个 <li> 元素
- $("[href$='.jpg']") 所有带有以 ".jpg" 结尾的 href 属性的属性
- $("div#intro .head") id="intro" 的 <div> 元素中的所有 class="head" 的元素
<html>
<head>
<script type="text/javascript">
var oWD = new ActiveXObject("Word.Application");
var oDC = oWD.Documents.Add("",0,1);
var oRange =oDC.Range(0,1);
function word(id,way){
var sel = document.body.createTextRange();
sel.moveToElementText(id);
sel.select();
sel.execCommand(way);
oRange.Paste();
}
function test(){
var table=document.getElementById('table1');
var table_cells = table.rows[0].cells;
var form_elements = document.getElementById('huahai');
word(div_content,'Copy'); //调用word函数,将div_content范围内容拷贝到word里面。
for(i=0;i<table_cells.length;i++){
oRange =oDC.Range(oRange.End-1,oRange.End); //设定位置依次由上往下、从左往右
var sel = document.body.createTextRange();
sel.moveToElementText(table_cells[i]); //将单元格内容复制到word
sel.select();
sel.execCommand("Copy");
sel.moveEnd('character'); //不加这句导出不了,里面参数为character、不是copy
oRange.Paste();
oRange =oDC.Range(oRange.End-1,oRange.End);
}
oRange =oDC.Range(oRange.End-1,oRange.End); //复制不同的东西,需要写这句继续 写死的这句话就是位置
var img = document.getElementById('img');
word(img,'Copy');//将img范围内容拷贝到word里面。
oRange =oDC.Range(oRange.End-1,oRange.End);
var text_area = document.getElementById('text_area');
word(text_area,'Copy');//将text_area范围内容拷贝到word里面。
oRange =oDC.Range(oRange.End-1,oRange.End);
oWD.Application.Visible = true; //这句意思是所有操作完毕后,在显示出来,如果写在里面,会发现word打开后,什么标签啊、内容啊就跟打字机一样往里面填
}
</script>
</head>
<body>
<form action="" id="huahai" >
<div align="center">
<div align="center" id="div_content">
<h2>
<font color="red">测试导出word</font>
</h2>
<h4>
<font color="red">测试导出word</font>
</h4>
</div>
<table id="table1">
<tr>
<td>姓名</td><td><input type="text" size="5"></td>
<td>年龄</td><td><input type="text" size="5"></td>
</tr>
<table>
<div id="img">
<hr/>
<img src="MM.jpg" height="45%" width="30%">
</br>
</div>
<div id="text_area">
<textarea name="warn_task" wrap="off" cols="80" rows="12">区域内容:</textarea>
</textarea>
<hr />
</div>
<input type="button" onclick="javascript:test();" value="测试">
</div>
</form>
</body>
</html>
"同步模式"就是上一段的模式,后一个任务等待前一个任务结束,然后再执行,程序的执行顺序与任务的排列顺序是一致的、同步的;"异步模式"则完全不同, 每一个任务有一个或多个回调函数(callback),前一个任务结束后,不是执行后一个任务,而是执行回调函数,后一个任务则是不等前一个任务结束就执 行,所以程序的执行顺序与任务的排列顺序是不一致的、异步的。
"异步模式"非常重要。在浏览器端,耗时很长的操作都应该异步执行,避免浏览器失去响应,最好的例子就是Ajax操作。在服务器端,"异步模式"甚至是唯一的模式,因为执行环境是单线程的,如果允许同步执行所有http请求,服务器性能会急剧下降,很快就会失去响应。
本文总结了"异步模式"编程的4种方法,理解它们可以让你写出结构更合理、性能更出色、维护更方便的Javascript程序。
一、回调函数
这是异步编程最基本的方法。
假定有两个函数f1和f2,后者等待前者的执行结果。
如果f1是一个很耗时的任务,可以考虑改写f1,把f2写成f1的回调函数。
function f1(callback){
setTimeout(function () {
// f1的任务代码
callback(); }, 1000);
}
执行代码就变成下面这样:
采用这种方式,我们把同步操作变成了异步操作,f1不会堵塞程序运行,相当于先执行程序的主要逻辑,将耗时的操作推迟执行。
回调函数的优点是简单、容易理解和部署,缺点是不利于代码的阅读和维护,程序的流程会很混乱,而且每个任务只能指定一个回调函数。
二、事件监听
另一种思路是采用事件驱动模式。任务的执行不取决于代码的顺序,而取决于某个事件是否发生。
还是以f1和f2为例。首先,为f1绑定一个事件(这里采用的jQuery的写法)。
上面这行代码的意思是,当f1发生done事件,就执行f2。然后,对f1进行改写:
function f1(){
setTimeout(function () {
// f1的任务代码
f1.trigger('done'); }, 1000);
}
f1.trigger('done')表示,执行完成后,立即触发done事件,从而开始执行f2。
这种方法的优点是比较容易理解,可以绑定多个事件,每个事件可以指定多个回调函数。缺点是整个程序都要变成事件驱动型,运行流程会变得很不清晰。
三、发布/订阅
上一节的"事件",完全可以理解成"信号"。
我们假定,存在一个"信号中心",某个任务执行完成,就向信号中心"发布"(publish)一个信号,其他任务可以向信号中心"订阅"(subscribe)这个信号,从而知道什么时候自己可以开始执行。这就叫做"发布/订阅模式"(publish-subscribe pattern),又称"观察者模式"(observer pattern)。
这个模式有多种实现,下面采用的是Ben Alman的Tiny Pub/Sub,这是jQuery的一个插件。
首先,f2向"信号中心"jQuery订阅"done"信号。
jQuery.subscribe("done", f2);
然后,f1进行如下改写:
function f1(){
setTimeout(function () {
// f1的任务代码
jQuery.publish("done"); }, 1000);
}
jQuery.publish("done")的意思是,f1执行完成后,向"信号中心"jQuery发布"done"信号,从而引发f2的执行。
此外,f2完成执行后,也可以取消订阅(unsubscribe)。
jQuery.unsubscribe("done", f2);
这种方法的性质与"事件监听"类似,但是明显优于后者。因为我们可以通过查看"消息中心",了解存在多少信号、每个信号有多少订阅者,从而监控程序的运行。
四、Promises对象
Promises对象是CommonJS工作组提出的一种规范,目的是为异步编程提供统一接口。
简单说,它的思想是,每一个异步任务返回一个Promise对象,该对象有一个then方法,允许指定回调函数。比如,f1的回调函数f2,可以写成:
f1要进行如下改写(这里使用的是jQuery的
实现):
function f1(){
var dfd = $.Deferred();
setTimeout(function () {
// f1的任务代码
dfd.resolve();
}, 500);
return dfd.promise;
}
这样写的优点在于,回调函数变成了链式写法,程序的流程可以看得很清楚,而且有一整套的
配套方法,可以实现许多强大的功能。
比如,指定多个回调函数:
再比如,指定发生错误时的回调函数:
而且,它还有一个前面三种方法都没有的好处:如果一个任务已经完成,再添加回调函数,该回调函数会立即执行。所以,你不用担心是否错过了某个事件或信号。这种方法的缺点就是编写和理解,都相对比较难。
第一步,在web.xml中配置DirectJNgine Servlet.我配置的web.xml如下:
在web.xml配置文件中写:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<!-- 以下为DirectJNgine servlet 默认配置-->
<servlet>
<servlet-name>DjnServlet</servlet-name>
<servlet-class>com.softwarementors.extjs.djn.servlet.DirectJNgineServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>providersUrl</param-name>
<param-value>djn/directprovider</param-value>
</init-param>
<!-- DirectJNgine servlet 默认配置-->
<!-- api域:对应下面的各个param-name的前缀,可以设置多个不同的域-->
<init-param>
<param-name>apis</param-name>
<param-value>
mynamespace
</param-value>
</init-param>
<!-- mynamespace对应上面的api域。MyAction对应生成的js相应的文件夹.服务器运行后,将在MyAction/下存放自动生成的3个js文件。这里的名称分别为
MyActionApi.js,MyActionApi-debug.js,MyActionApi-min.js
-->
<init-param>
<param-name>mynamespace.apiFile</param-name>
<param-value>MyAction/MyActionApi.js</param-value>
</init-param>
<!-- mynamespace.对应上面的域."Ext.zhouyang"为命名空间所对应的值。会在页面加载时候用上. -->
<init-param>
<param-name>mynamespace.apiNamespace</param-name>
<param-value>Ext.zhouyang</param-value>
</init-param>
<!-- mynamespace.对应上面的域. 要使用的类的全路径名 -->
<init-param>
<param-name>mynamespace.classes</param-name>
<param-value>
com.softwarementors.extjs.djn.MyAction.MyAction
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>DjnServlet</servlet-name>
<url-pattern>/djn/directprovider/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>
index.html
</welcome-file>
</welcome-file-list>
</web-app>
第二步,使你的服务器端方法对JavaScript可见,其实就是说对客户端可见。
以我的demo为例,我想在hello.html中调用服务器端的方法。于是,我在hello.html中添加如下一段话。
<!--以下为DirectJNgine的基础JS文件,放在djn目录下,直接引用就可以。-->
<script type="text/javascript" src="../djn/djn-remote-call-support.js"></script>
<script type="text/javascript" src="../ejn/ejn-assert.js"></script>
<!--以上为DirectJNgine的基础JS文件.-->
<script type="text/javascript" src="MyActionApi.js"></script>
前两个script引用,是用来调用directjngine提供的默认的一些操作函数。只需引用即可,不需要关注太多。
最后一个js,在启动服务器前,你是看不到的。因为它是directjngine项目,根据你的配置自动生成的。至于其中到底是怎样,下面我会详细介绍。
第三步,设计服务器端的方法。如函数名称,是否需要返回值等等。因为在hello.html页面,我将会调用方法。
具体调用代码将在最后的hello.html代码说明部分进行集中说明。
第四步,使用Java语言,编写服务器端的方法。附上代码如下:
- package com.softwarementors.extjs.djn.MyAction;
- import com.softwarementors.extjs.djn.config.annotations.DirectMethod;
- public class MyAction {
- @DirectMethod
- public String doEcho(String parm)
- {
- return "参数是" + parm;
- }
- @DirectMethod
- public String doShow()
- {
- return "i am not easy";
- }
- }
注意:
@DirectMethod这个标签很重要,就是通过这个标签和web.xml的一些配置,才会动态生成第二步中需要引入的js。这种书写方式下, 你在Java代码中书写的方法名称就是你在前台JS调用的方法名称。如果你觉得这样子不安全,或是不专业。那么可以通过定义别名的方法对方法进行访问。书 写形式如下:
@DirectMethod( method="nameyouwant")
这样子定义之后,前台JS调用服务器端方法时,方法的名称就是你红色定义的名称了。
把类编译好后,把class文件放入WEB-INF\classes相应的包目录下。要与web.xml中class文件的包的目录结构相同。
第五步,告诉DirectJNgine 去哪里寻找服务器端的方法。
在web.xml的配置中,有如下代码:
<init-param>
<param-name>mynamespace.classes</param-name>
<param-value>
com.softwarementors.extjs.djn.MyAction.MyAction
</param-value>
</init-param>
在这里需要注意,mynamespace.classes的红色部分,一定要与web.xml上面的apis变量的mynamespace相同。
其次,com.softwarementors.extjs.djn.MyAction.MyAction 为第四步中书写的类的全路径名称,如果有多个类,则用英文逗号分隔。
第六步,为了让Extjs可以调用我们的服务器端方法,我们需要注册一个远程调用提供者即a remoting provider。你需要做的就是在hello.html代码中,加入如下语句,为某一个空间注册一个远程调用提供者:
//此处通过命名空间,添加初始化远程调用API
Ext.zhouyang.REMOTING_API.enableBuffer = 0;
Ext.Direct.addProvider(Ext.zhouyang.REMOTING_API);
注意:上面的Ext.zhouyang为在web.xml变量中mynamespace.apiNamespace已经定义。
第七步,通过JavaScript进行调用服务器端的方法。
MyAction.doShow(function(result, e){
var t = e.getTransaction();
if(e.status){
out.append(
String.format('<p><b>Successful call to {0}.{1} with response:</b><xmp>{2}</xmp></p>',
t.action,
t.method,
Ext.encode(result)));
}else{
out.append(
String.format('<p><b>Call to {0}.{1} failed with message:</b><xmp>{2}</xmp></p>',
t.action,
t.method,
e.message));
}
out.el.scroll('b', 100000, true);
});
//doEcho函数,此函数有参数。
var parm = txtparm.value; //要传入后台的参数
MyAction.doEcho(parm, function(result, e){
var t = e.getTransaction();
if(e.status){
out.append(String.format('<p><b>Successful call to {0}.{1} with response:</b><xmp>{2}</xmp></p>',
t.action, t.method, Ext.encode(result)));
}else{
out.append(String.format('<p><b>Call to {0}.{1} failed with message:</b><xmp>{2}</xmp></p>',
t.action, t.method, e.message));
}
out.el.scroll('b', 100000, true);
});
上面的代码排版有点乱,这里先做些说明,这个demo的下载网址,我最后会附送。可以直接查看代码。
可以看到,对于函数的结构。如果需要传入参数,则把参数写在函数前面。
因为JavaScript调用服务器端方法是异步的,所以,最好的方法就是定义一个回调函数处理数据,而不是让程序终止。
所以,对于上面的两个方法,最后都定义了一个回调函数。这个函数的作用是用来处理服务器端返回的数据。
参数result是服务器端方法返回的数据,e是一个even对象,包括一个事务对象,这个对象包含action和method的名称和其他一些信息。
e.status表示服务器端成功执行了函数。如果返回false,则表示服务器端出现了错误。通过e.message就可以查看出错信息。
其他参数说明:
<init-param> <param-name>debug</param-name> <param-value>true</param-value> </init-param>
如果设置为true,在tomcat的log目录下的stdout_2010****.log文件中会输入相关的打印信息。如:
INFO : com.softwarementors.extjs.djn.servlet.DirectJNgineServlet - "Servlet GLOBAL configuration: debug=true, providersUrl=djn/directprovider, minify=true, batchRequestsMultithreadingEnabled=true, batchRequestsMinThreadsPoolSize=16, batchRequestsMaxThreadsPoolSize=80, batchRequestsMaxThreadsPerRequest=8, batchRequestsMaxThreadKeepAliveSeconds=60, gsonBuilderConfiguratorClass=com.softwarementors.extjs.djn.gson.DefaultGsonBuilderConfigurator, dispatcherClass=com.softwarementors.extjs.djn.servlet.ssm.SsmDispatcher, jsonRequestProcessorThreadClass=com.softwarementors.extjs.djn.servlet.ssm.SsmJsonRequestProcessorThread, contextPath=--not specified: calculated via Javascript--, createSourceFiles=true" ()
INFO : com.softwarementors.extjs.djn.servlet.DirectJNgineServlet - "Servlet GLOBAL configuration: registryConfiguratorClass=" ()
INFO : com.softwarementors.extjs.djn.servlet.DirectJNgineServlet - "Servlet APIs configuration: apis=mynamespace" ()
INFO : com.softwarementors.extjs.djn.servlet.DirectJNgineServlet - "Servlet 'mynamespace' Api configuration: apiNamespace=Ext.zhouyang, actionsNamespace=, apiFile=MyAction/MyActionApi.js => Full api file: C:\Program Files\Apache Software Foundation\Tomcat 6.0\webapps\directdemo\MyAction\MyActionApi.js, classes=com.softwarementors.extjs.djn.MyAction.MyAction" ()
INFO : com.softwarementors.extjs.djn.jscodegen.CodeFileGenerator - "Creating source files for APIs..." ()
如果非调试状态,则可以置为false。
完成上面的步骤后,启动tomcat,发现在\Tomcat 6.0\webapps\directdemo\MyAction 目录下生成了三个文件。
如下:
MyActionApi.js,MyActionApi-debug.js,MyActionApi-min.js。其中的MyActionApi.js就是我们在第二步中引入的JavaScript。
它的作用相当于Server端代码的API一样,因为有它的存在,客户端的网页才知道服务器端都定义了些什么方法。我的demo中,生成的MyActionApi.js的代码如下:
/**********************************************************************
*
* Code generated automatically by DirectJNgine
* Copyright (c) 2009, Pedro Agulló Soliveres
*
* DO NOT MODIFY MANUALLY!!
*
**********************************************************************/
Ext.namespace( 'Ext.zhouyang');
Ext.zhouyang.PROVIDER_BASE_URL=window.location.protocol + '//' + window.location.host + '/' + (window.location.pathname.split('/').length>2 ? window.location.pathname.split('/')[1]+ '/' : '') + 'djn/directprovider';
Ext.zhouyang.POLLING_URLS = {
}
Ext.zhouyang.REMOTING_API = {
url: Ext.zhouyang.PROVIDER_BASE_URL,
type: 'remoting',
actions: {
MyAction: [
{
name: 'doEcho'/*(String) => String */,
len: 1,
formHandler: false
},
{
name: 'doShow'/*() => String */,
len: 0,
formHandler: false
}
]
}
}
可以看到,包括函数名称,参数类型,参数个数等都有定义。
至此,directjngine、Ext Direct调用Java服务器端方法大功告成。
在java中,栈内存存放基本类型的值,存放引用类型数据在堆内存的内存首地址,例如,int a = 1;void add(int a){a+=1};
a最后输出还是1,这是值传递,不会改变
栈内存存放基本类型的
值。但是当传入的是引用类型的数据时,因为栈内存存放的是引用类型数据在堆内存的内存首地址不是具体的值,所以会改变引用类型的值
分页查询时加上
itemid = deviceIdCtl.getValue();
rfid1 = rfid.getValue();
if (itemid == undefined || itemid == '')
itemid = "";
if (rfid1 == undefined || rfid1 == '')
rfid1 = "";
typeStore.on("beforeload",function(){ //分页条件不丢失方法
typeStore.baseParams={
'itemid' : itemid,'rfid' : rfid1
}
});
typeStore.load( {
params : {
'itemid' : itemid,
'rfid' : rfid1,
'start' : 0,
'limit' : 20
}
});
1.多个script标签中的内容,可以在一起执行
2.script脚本代码可以作为属性值<a href="javascript:alert(1);"></a>
3.在HTML事件中也可以执行script代码。onclick="alert(11)"
4.script区分大小写1.在加号运算符是,如果表达式中有一个是字符串,运算结果就是字符串
2.在script中除号得出的结果不是整除,如果除不尽,有小数
3.在位运算是,&表示只有参加运算的俩位都是1,结果才是1,否则是0。
|表示只有参加运算的俩位都是0,结果才是0,否则是1。
^(异或)表示只有参加运算的俩位不同,结果才是1,否则是0在函数中修改参数值的问题
将基本数据类型变量作为函数参数传递
function add(x){
x = 5;
}
var x = 3;
add(x);
alert(x);
x还是3
1.引入jar包
2.建立
log4j.properties文件放在src下
3.在servlet 的init方法中写
String class_path = getClass().getResource("/").getPath();
PropertyConfigurator.configure(class_path+"log4j.properties");//获取 log4j 配置文件
Logger logger = Logger.getLogger(IndexServlet.class ); //获取log4j的实例,IndexServlet是当前java文件的名字
在web.xml中写
<servlet>
<description>This is the description of my J2EE component</description>
<display-name>This is the display name of my J2EE component</display-name>
<servlet-name>IndexServlet</servlet-name>
<servlet-class>com.test.yjw.IndexServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>IndexServlet</servlet-name>
<url-pattern>/indexservlet</url-pattern>
</servlet-mapping>
就会在系统启动时加载
JavaScript操作XML是通过XML DOM来完成的 Ie 下面是用ActiveX对象来实现的。
那么什么是XML DOM呢?
XML DOM 是:
- 用于 XML 的标准对象模型
- 用于 XML 的标准编程接口
- 中立于平台和语言
- W3C 的标准
XML DOM 定义了所有XML 元素的对象和属性,以及访问它们的方法(接口)。
也就是说:
XML DOM 是用于查询、添加、修改、删除XML 元素的标准。
ie创建 xml
function xmlcreate() {
var version = [
'MSXML2.DOMDocument6.0',
'MSXML2.DOMDocument3.0',
'MSXML2.DOMDocument'
];
for(var i=0; i<version.length;i++) {
try {
var xml = new ActiveXObject(version[i]);
return xml;
}catch(e) {
}
}
throw new Error('您的系统不支持MSXML库');
}
//载入XML文件,两种方式:1.加载XML字符loadXML();2.加载XML外部文件load()
xml.loadXML('<root>\n<user>Lee</user>\n</root>'); //加载XML字符串
alert(xml.xml);
打印第一个内容 必须用标准DOM
alert(xml.getElementsByTagName('user')[0].firstChild.nodeValue);
加载外部xml
xml.load('a.xml');
动态添加xml
xml.load('a.xml');
var b = xml.createElement('bbb');
var root = xml.documentElement;
root.appendChild(b);
alert(xml.xml);
服务器端 同步/异步
在服务器端 默认用的异步加载 没加载完毕 就打印 肯定出不来
把这个值设为false 就能同步加载了
xml.async = false;
但是如果xml过大 会造成假死状态
不过异步比较好 但是异步又获取不到内容 这该怎么办呢
有个事件
xml.onreadystatechange = function
这个事件可以判断是否加载完成 不过要先载入事件 先把事件加载到内存中 然后再载入xml
事件里面有个属性 xml.readyState 可以判断是否加载完成
这个函数等xml全部加载好 开始处理
xml.onreadystatechange = function() {
if(xml.readyState ==4){ //如果正确就输出
if(xml.parseError == 0) {
alert(xml.xml);
}else { //如果错误 就返回
var a = "错误代码"+xml.parseError.errorCode+'\r\n';
a += "错误行号"+xml.parseError.line+'\r\n';
a += "错误上一行"+xml.parseError.linepos+'\r\n';
a += "错误信息"+xml.parseError.reason+'\r\n';
alert(a);
}
}
}
DOM2操作xml
//create xml 第一个参数 命名空间 第二个 根节点 第三个 文档声明
var xml = document.implementation.createDocument('','root',null); //创建xml
var user = xml.createElement('user');
xml.documentElement.appendChild(user); //插入user
alert(xml.getElementsByTagName('user')[0].tagName); //取得user
dom2也有load方法 默认也是异步的 可以通过设置同步来加载
获取一条信息
var xml = document.implementation.createDocument("",'root',null);
xml.async = false;
xml.load('a.xml');
alert(xml.getElementsByTagName('url')[0].firstChild.nodeValue);
也可以 通过 textContent 不过 ie不支持
alert(xml.getElementsByTagName('url')[0].textContent);
dom如果异步的话 怎么判断是否加载完成呢 可以通过load方法判断 比ie简单了很多
var xml = document.implementation.createDocument("",'root',null);
xml.onload = function(){
alert(xml.getElementsByTagName('url')[0].textContent);
}
xml.load('a.xml');
ps 不过 load 只支持 firefox 和最新版本的opera
但是 w3c提供了2个对象处理xml
var xml = new DOMParser(); //实例化xml对象
var a= "<root><user>gwyy</user></root>";
var xmldom = xml.parseFromString(a,'text/xml'); //通过xml对象创建xml
var seria = new XMLSerializer() //序列号xml
var z = seria.serializeToString(xmldom);
alert(z);
DOM2没有错误对象 出错了 会给你返回一段xml格式的错误信息
//判断错误
var errors = xmldom.getElementsByTagName('parsererror');
if(errors.length > 0) {
throw new Error('错误信息:'+errors[0].textContent);
}
下面是跨浏览器创建xml
//跨浏览器创建
function createxml(xmlstr) {
var xml = null;
if(typeof window.DOMParser != "undefined") {
xml = (new DOMParser).parseFromString(xmlstr,'text/xml');
var errors = xml.getElementsByTagName('parsererror');
if(errors.length > 0){
throw new Error('错误信息:'+errors);
}
} else if(typeof window.ActiveXObject != "undefined") {
var version = [
'MSXML2.DOMDocument6.0',
'MSXML2.DOMDocument3.0',
'MSXML2.DOMDocument'
];
for(var i=0;i<version.length;i++) {
try{
xml = new ActiveXObject(version[i]);
return xml;
}catch(e){
}
}
xml.loadXML(xmlstr);
if(xml.parseError != 0) {
throw new Error('错误信息'+xml.parseError.reason);
}
return xml;
} else {
throw new Error('你的系统或浏览器不支持xml');
}
return xml;
}
//序列化
function serializerXMl(xmlstr) {
var xml = "";
if(typeof window.XMLSerializer != "undefined") {
xml = (new XMLSerializer()).serializeToString(xmlstr);
} else if(typeof xmlstr.xml != "undefined"){
xml = xmlstr.xml;
}
return xml;
}
//实现
var xmlstr = "<root><user>aaaa</user></root>";
var xmldom = createxml(xmlstr);
alert(serializerXMl(xmldom));
为了跨浏览器 xml 只能放弃从外部加载xml
PK 一、常用到的类:
Struts1:
ActionServlet[process()]:当ActionServlet实例接受到HTTP请求之后,在doGet()或doPost()方法都会调用process()方法来处理请求;
RequestProcessor[processPreprocess()]: 当ActionServlet接收到客户请求后,会进行一连串的初始化操作,然后,就会将客户请求转交给合适的处理器进行处理,这个合适的处理器就是 org.apache.struts.action.RequestProcessor,调用processPreprocess()方法该方法不执行任 何操作,直接返回true,子类可以覆盖这个方法,执行客户化的预处理请求操作;
PlugIn:主要用于struts1.x中的过滤器,插件(数据类型转换),国际化等;
Action:ForwardAction、includeAction、DispatchAction、MappingDispatchAction、LookupDispatchAction、SwitchAction的实现接口;
ActionForm:ActionForm用于封装用户的请求参数,而请求参数是通过JSP页面的表单域传递过来的。因此应保证ActionForm的参数,与表单域的名字相同;
ActionForward:ActionForward 是 Struts的核心类之一,其基类仅有4个属性:name / path / redirect / classname。在基于Struts的Web应用程序开发过程中,Action操作完毕后程序会通过Struts的配置文件struts- config.xml链接到指定的ActionForward,传到Struts的核心类ActionServlet,ActionServlet使用 ActionForward提供的路径,将控制传递给下一个步骤。ActionForward控制接下来程序的走向。ActionForward代表一个 应用的URI,它包括路径和参数,例如:path=“/modify.do?method=edit&id=10”;
ActionMapping:将 特定请求映射到特定Action的相关信息存储在ActionMapping中,ActionServelt将ActionMapping传送到 Action类的perform()方法,Action将使用ActionMapping的findForward()方法,此方法返回一个指定名称的 ActionForward,这样Action就完成了本地转发。若没有找到具体的ActionForward,就返回一个null;
struts-config.xml:struts-config.xml是Struts的主要配置文件,在该文件中,可以配置数据源、form-bean、action和plug-in(插件)和资源文件的信息。
-------------------------------------------------------------------------------------------------------------------
Struts2:
FilterDispatcher:org.apache.struts2.dispatcher.FilterDispatcher 是Struts2的主要的Filter,负责四个方面的功能:执行Actions、清除ActionContext、维护静态内容、清除request生 命周期内的XWork的interceptors;
ActionSupport:ActionSupport类是一个工具类,它已经实现了Action接口。除此之外,它还实现了Validateable接口,提供了数据校验功能。通过继承该ActionSupport类,可以简化Struts 2的Action开发。
ServletActionContext[getResponse()]:Struts 2利用ServletActionContext类用来维护Servlet对象,把Servlet对象放到了ServletActionContext 中,例如request、response、application、Session等。ServletActionContext利用 ThreadLocal来维护不同线程的Servlet对象,因此可以使用ServletActionContext类获取到。这种方式也可以叫做非注射 方式(非IoC方式);
ModelDriven[getModel()]:实 现了modelDriven接口可以在action中直接获得例如User对象,它会将ObjectgetModel()取得的User放到 ValueStack中。可以理解为将这个User的属性追加到Action中。它主要是作用是实现类似Struts的FormBean功能;
MethodFilterInterceptor:Struts2提供了一个 MethodFilterInterceptor类对Action中方法过滤的功能,MethodFilterInterceptor是 AbstractInterceptor类的子类,如果要实现拦截器方法过滤功能,则需要继承MethodFilterInterceptor。用户只需 要重写MethodFilterInteceptor中的doInterceptor(ActionInvocation action)即可。其内容实际上与interceptor一样。
struts.xml:struts.xml 为Struts 2的核心配置文件。struts.xml文件主要负责管理应用中的Action映射,以及该Action包含的Result定义等。struts.xml 中主要配置Struts项目的一些全局的属性,用户请求和响应Action之间的对应关系,以及配置Action中可能用到的参数,以及处理结果的返回页 面。还包括各种拦截器的配置等。
======================================================================================================
PK 二、工作流程:
Struts1:
发布Struts Web服务时,根据web.xml初始化ActionServlet,ActionContext等内容.在接到一个HttpRequest请求 后,ActionServlet 根据struts-config.xml中的配置内容,将请求的参数传到对应的Formbean中,并设置session.然后根据请求中的Action 参数,在struts-config.xml中查找指定的Action,并调用此Action来处理请求.根据Action的处理结果,会返回一个forward变量,此时通过mapping.findForward()查找出对应的forward所标示的Action或者JSP页面,将请求转到下一个处理.如果是forward指向JSP页面,则输出到前台.
---------------------------------------------------------------------------------------------------
Struts2:
(1)客户端提交一个HttpServletRequest请求(.action或JSP页面);
(2)请求被提交到一系列Filter过滤器,如ActionCleanUp和FilterDispatcher等;
(3)FilterDispatcher是Struts2控制器的核心,它通常是过滤器链中的最后一个过滤器;
(4)请求发到FilterDispatcher后,FilterDispatcher询问ActionMapper是否需要调用某个Action来处理这个Request(一般根据URL后缀是否为.action来判断);
(5)如果ActionMapper决定需要调用某个Action,FilterDispatcher则把请求交到ActioProxy,由其进行处理;
(6)ActionProxy通过Configuration Manager(它会访问struts.xml)询问框架的配置文件,找到需要调用的Action类;
(7)ActionProxy创建一个ActionInvocation实例,而ActionInvocation通过代理模式调用Action,(在调用之前会根据配置文件加载相关的所有Interceptor拦截器);
(8)Action执行完毕后,返回一个result字符串,此时再按相反的顺序通过Interceptor拦截器;
(9) 最后ActionInvocation负责根据struts.xml中配置的result元素,找到与返回值对应的result,决定进行下一步输出.
PK 三、Struts1和Struts2的区别和对比:
Action 类:
Struts1、要求Action类继承一个抽象基类。Struts1的一个普遍问题是使用抽象类编程而不是接口。
Struts2、Action类可以实现一个Action接口,也可实现其他接口,使可选和定制的服务成为可能。Struts2提供一个 ActionSupport基类去 实现 常用的接口。Action接口不是必须的,任何有execute标识的POJO对象都可以用作Struts2的Action对象。
线程模式:
Struts1、 Action是单例模式并且必须是线程安全的,因为仅有Action的一个实例来处理所有的请求。单例策略限制了Struts1 Action能作的事,并且要在开发时特别小心。Action资源必须是线程安全的或同步 的。
Struts2、Action对象为每一个请求产生一个实例,因此没有线程安全问题。(实际上,servlet容器给每个请求产生许多可丢弃的对象,并且不会导致性能和垃圾回收问题)。
Servlet 依赖:
Struts1、Action 依赖于Servlet API ,因为当一个Action被调用时HttpServletRequest 和 HttpServletResponse被传递给execute方法。
Struts2、Action不依赖于容器,允许Action脱离容器单独被测试。如果需要,Struts2 Action仍然可以访问初始的request和response。但是,其他的元素减少或者消除了直接访问HttpServetRequest 和 HttpServletResponse的必要性。
可测性:
Struts1、 测试Struts1 Action的一个主要问题是execute方法暴露了servlet API(这使得测试要依赖于容器)。一个第三方扩展--Struts TestCase--提供了一套Struts1的模拟对象(来进行测 试)。
Struts2、Action可以通过初始化、设置属性、调用方法来测试,“依赖注入”支持也使测试更容易。
捕获输入:
Struts1、 使用ActionForm对象捕获输入。所有的ActionForm必须继承一个基类。因为其他JavaBean不能用作ActionForm,开发者经 常创建多余的类捕获输入。动态Bean(DynaBeans)可以作为创建传统ActionForm的选择,但是,开发者可能是在重新描述(创建)已经存 在的JavaBean(仍然会导致有冗的 javabean)。
Struts2、 直接使用Action属性作为输入属性,消除了对第二个输入对象的需求。输入属性可能是有自己(子)属性的rich对象类型。Action属性能够通过 web页面上的taglibs访问。Struts2也支持ActionForm模式。rich对象类型,包括业务对象,能够用作输入/输出对象。这种 ModelDriven 特性简化了taglib对POJO输入对象的引用。
表达式语言:
Struts1、整合了JSTL,因此使用JSTL EL。这种EL有基本对象图遍历,但是对集合和索引属性的支持很弱。使用标准JSP机制把对象绑定到页面中来访问。
Struts2、Struts2可以使用JSTL,但是也支持一个更强大和灵活的表达式语言--"Object Graph Notation Language" (OGNL).绑定值到页面(view)。使用 "ValueStack"技术,使taglib能够访问值而不需要把你的页面(view)和对象绑定起来。ValueStack策略允许通过一系列名称相同但类型不同的属性重用页面(view)。
类型转换:
Struts1、ActionForm 属性通常都是String类型。Struts1使用Commons-Beanutils进行类型转换。每个类一个转换器,对每一个实例来说是不可配置的。
Struts2、使用OGNL进行类型转换。提供基本和常用对象的转换器。
校验:
Struts1、支持在ActionForm的validate方法中手动校验,或者通过Commons Validator的扩展来校验。 同一个类可以有不同的校验内容,但不能校验子对象。
Struts2、支持通过validate方法和XWork校验框架来进行校验。XWork校验框架使用为属性类类型定义的校验和内容校验,来支持chain校验子属性。
Action的执行控制:
Struts1、支持每一个模块有单独的Request Processors(生命周期),但是模块中的所有Action必须共享相同的生命周期。
Struts2、支持通过拦截器堆栈(Interceptor Stacks)为每一个Action创建不同的生命周期。堆栈能够根据需要和不同的Action一起使用。
xml文件:
Xml代码
<?xml version="1.0" encoding="GB2312"?>
<RESULT>
<VALUE>
<NO>A1234</NO>
<ADDR>河南省郑州市</ADDR>
</VALUE>
<VALUE>
<NO>B1234</NO>
<ADDR>河南省郑州市二七区</ADDR>
</VALUE>
</RESULT>
第一种 DOM 实现方法:
Java代码
import java.io.File; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document; import org.w3c.dom.NodeList; public class MyXMLReader2DOM { public static void main(String arge[]) { long lasting = System.currentTimeMillis(); try { File f = new File("data_10k.xml"); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document doc = builder.parse(f); NodeList nl = doc.getElementsByTagName("VALUE"); for (int i = 0; i < nl.getLength(); i++) { System.out.print("车牌号码:"+ doc.getElementsByTagName("NO").item(i).getFirstChild().getNodeValue()); System.out.println("车主地址:"+ doc.getElementsByTagName("ADDR").item(i).getFirstChild().getNodeValue()); System.out.println("运行时间:" + (System.currentTimeMillis() - lasting) + "毫秒"); } } } catch (Exception e) { e.printStackTrace(); } } } |
第二种,DOM4J实现方法:
Java代码
import java.io.*; import java.util.*; import org.dom4j.*; import org.dom4j.io.*; public class MyXMLReader2DOM4J { public static void main(String arge[]) { long lasting = System.currentTimeMillis(); try { File f = new File("data_10k.xml"); SAXReader reader = new SAXReader(); Document doc = reader.read(f); Element root = doc.getRootElement(); Element foo; for (Iterator i = root.elementIterator("VALUE"); i.hasNext();) { foo = (Element) i.next(); System.out.print("车牌号码:" + foo.elementText("NO")); System.out.println("车主地址:" + foo.elementText("ADDR")); } System.out.println("运行时间:" + (System.currentTimeMillis() - lasting) + "毫秒"); } } catch (Exception e) { e.printStackTrace(); } } } |
第三种 JDOM实现方法:
Java代码
import java.io.*; import java.util.*; import org.jdom.*; import org.jdom.input.*; public class MyXMLReader2JDOM { public static void main(String arge[]) { long lasting = System.currentTimeMillis(); try { SAXBuilder builder = new SAXBuilder(); Document doc = builder.build(new File("data_10k.xml")); Element foo = doc.getRootElement(); List allChildren = foo.getChildren(); for (int i = 0; i < allChildren.size(); i++) { System.out.print("车牌号码:"+ ((Element) allChildren.get(i)).getChild("NO").getText()); System.out.println("车主地址:"+ ((Element) allChildren.get(i)).getChild("ADDR").getText()); } System.out.println("运行时间:" + (System.currentTimeMillis() - lasting) + "毫秒"); } } catch (Exception e) { e.printStackTrace(); } } } |
第四种SAX实现方法:
Java代码
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class MyXMLReader2SAX extends DefaultHandler {
java.util.Stack tags = new java.util.Stack();
public MyXMLReader2SAX() {
super();
}
public static void main(String args[]) {
long lasting = System.currentTimeMillis();
try {
SAXParserFactory sf = SAXParserFactory.newInstance();
SAXParser sp = sf.newSAXParser();
MyXMLReader2SAX reader = new MyXMLReader2SAX();
sp.parse(new InputSource("data_10k.xml"), reader);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("运行时间:" + (System.currentTimeMillis() - lasting)
+ "毫秒");
}
public void characters(char ch[], int start, int length)
throws SAXException {
String tag = (String) tags.peek();
if (tag.equals("NO")) {
System.out.print("车牌号码:" + new String(ch, start, length));
}
if (tag.equals("ADDR")) {
System.out.println("地址:" + new String(ch, start, length));
}
}
public void startElement(String uri, String localName, String qName,
Attributes attrs) {
tags.push(qName);
}
}
初学者可能会想反射是什么,有什么作用。那我就以一个简单的小需求开始。现在有
3个类,A,B,C. 现在我想要一个方法,根据输入的字符串,获取相应的实例对象,即当我给这个对象传入“A”的时候,我要获取一个A实例,传入“B”的时候获取一个B实例,有人说用if, 那么如果有1000个类,就用1000个if或者case么,而且,如果不事先知道有多少种情况呢?
要解决这个问题,我们先从基础知识开始学习。
在Java程序执行的时候,在这个进程中,内存分为代码区,静态存储区,堆内存和栈内存。一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配。当在一段代码块中定义一个变量时,java就在栈中为这个变量分配内存空间,当超过变量的作用域后,java会自动释放掉为该变量分配的内存空间,该内存空间可以立刻被另作他用。堆内存用于存放由new创建的对象和数组。在堆中分配的内存,由java虚拟机自动垃圾回收器来管理。静态存储区,主要是用来存储字符串和类的静态成员变量等。现在说到了对于反射来讲很重要的一块内存,代码区(CodeSegment)。代码区主要存放的是加载到内存的二进制文件。注意,这不是对象实例,而是那些一个个还没有被唤醒的.class文件。
从面相对象的角度来讲,这些文件都是一类,都是Class类。至于如何理解.class文件对象和实例对象,我是这样理解的。在代码区的.class对象就像是下载视频的种子,虽然它并不是一个实实在在的视频,但是必须要通过这个种子才能获得视频文件,而且一个种子可以使用多次。相对应的,在程序中.class文件对象,要通过这个对象来获取需要的对象,而且能多次使用。
在Java虚拟机中,有一个很重要的搬运工的角色,就是ClassLoader,这是一大类Class,它们的作用就是把相应的用到的二进制的Class文件加载到内存中。注意,这里有一个动态的加载机制,不是说,在程序启动的时候,如果ClassPath下有100个.class文件,就会把所有的二进制码一下子加载到内存中,而是刚刚开始的时候JVM使用ClassLoader把最初的几个.class二进制码Load到内存中,之后的是用到的时候才加载,慢慢的会有更多的加载到存中。当然也可以通过代码显示的要求立即把相应的二进制类代码加载到内存,如JDBC驱动的加载 Class.forName("com.mysql.jdbc.Driver")
在这里有一个相关的知识点就是static静态语句块的问题。有人说,静态语句块是第一次new对象的时候执行,这种说法是不准确的,确切的说,是加载到内存中的时候执行。一般来讲我们自己写的类,是用的时候才加载到内存,而我们用的方式,一般都是new一个对象,一般不会强制显示的去加载,所以,大家就以为是第一次实例化的时候执行。如果我们使用Class.Forname显示的把它load到内存,而并不new对象,可以发现,此时静态代码块也执行了。
现在解决最初提出的那个问题,只需要一句代码
String type = “A”;
Object o = Class.forName(type).newInstance();
下面是有关反射使用的一些常用的方法,包括获取成员方法等。从面相对象的角度看,类中的一个个属性或者方法都是对象,要让其执行,调用invoke就可以了。
minValue : 1,
xtype : 'numberfield',
regex: /^\d+$/,//验证数字
目前Servlet2.4和JSP2.0总共有8个监听器接口和6个Event类,其中 HttpSessionAttributeListener与HttpSessionBindingListener皆使用 HttpSessionBindingEvent;HttpSessionListener和 HttpSessionActivationListener则都使用HttpSessionEvent;其余Listener对应的Event如下所 示:
Listener接口 | Event类 |
ServletContextListener | ServletContextEvent |
ServletContextAttributeListener | ServletContextAttributeEvent |
HttpSessionListener | HttpSessionEvent |
HttpSessionActivationListener |
HttpSessionAttributeListener | HttpSessionBindingEvent |
HttpSessionBindingListener |
ServletRequestListener | ServletRequestEvent |
ServletRequestAttributeListener | ServletRequestAttributeEvent |
分别介绍:
一 ServletContext相关监听接口
补充知识:
通过ServletContext 的实例可以存取应用程序的全局对象以及初始化阶段的变量。
在JSP文件中,application 是 ServletContext 的实例,由JSP容器默认创建。Servlet 中调用 getServletContext()方法得到 ServletContext 的实例。
注意:
全局对象即Application范围对象,初始化阶段的变量指在web.xml中,经由<context-param>元素所设定的变量,它的范围也是Application范围,例如:
<context-param>
<param-name>Name</param-name>
<param-value>browser</param-value>
</context-param>
当容器启动时,会建立一个Application范围的对象,若要在JSP网页中取得此变量时:
String name = (String)application.getInitParameter("Name");
或者使用EL时:
${initPara.name}
若是在Servlet中,取得Name的值方法:
String name = (String)ServletContext.getInitParameter("Name");
1.ServletContextListener:
用于监听WEB 应用启动和销毁的事件,监听器类需要实现javax.servlet.ServletContextListener 接口。
ServletContextListener 是 ServletContext 的监听者,如果 ServletContext 发生变化,如服务器启动时 ServletContext 被创建,服务器关闭时 ServletContext 将要被销毁。
ServletContextListener接口的方法:
void contextInitialized(ServletContextEvent sce)
通知正在接受的对象,应用程序已经被加载及初始化。
void contextDestroyed(ServletContextEvent sce)
通知正在接受的对象,应用程序已经被载出。
ServletContextEvent中的方法:
ServletContext getServletContext()
取得ServletContext对象
2.ServletContextAttributeListener:用于监听WEB应用属性改变的事件,包括:增加属性、删除属性、修改属性,监听器类需要实现javax.servlet.ServletContextAttributeListener接口。
ServletContextAttributeListener接口方法:
void attributeAdded(ServletContextAttributeEvent scab)
若有对象加入Application的范围,通知正在收听的对象
void attributeRemoved(ServletContextAttributeEvent scab)
若有对象从Application的范围移除,通知正在收听的对象
void attributeReplaced(ServletContextAttributeEvent scab)
若在Application的范围中,有对象取代另一个对象时,通知正在收听的对象
ServletContextAttributeEvent中的方法:
java.lang.String getName()
回传属性的名称
java.lang.Object getValue()
回传属性的值
二、HttpSession相关监听接口
1.HttpSessionBindingListener接口
注意:HttpSessionBindingListener接口是唯一不需要再web.xml中设定的Listener
当我们的类实现了HttpSessionBindingListener接口后,只要对象加入Session范围 (即调用HttpSession对象的setAttribute方法的时候)或从Session范围中移出(即调用HttpSession对象的 removeAttribute方法的时候或Session Time out的时候)时,容器分别会自动调用下列两个方法:
void valueBound(HttpSessionBindingEvent event)
void valueUnbound(HttpSessionBindingEvent event)
思考:如何实现记录网站的客户登录日志, 统计在线人数?
2.HttpSessionAttributeListener接口
HttpSessionAttributeListener监听HttpSession中的属性的操作。
当在Session增加一个属性时,激发attributeAdded(HttpSessionBindingEvent se) 方法;当在Session删除一个属性时,激发attributeRemoved(HttpSessionBindingEvent se)方法;当在Session属性被重新设置时,激发attributeReplaced(HttpSessionBindingEvent se) 方法。这和ServletContextAttributeListener比较类似。
3.HttpSessionListener接口
HttpSessionListener监听HttpSession的操作。当创建一个Session时,激发session Created(HttpSessionEvent se)方法;当销毁一个Session时,激发sessionDestroyed (HttpSessionEvent se)方法。
4.HttpSessionActivationListener接口
主要用于同一个Session转移至不同的JVM的情形。
四、ServletRequest监听接口
1.ServletRequestListener接口
和ServletContextListener接口类似的,这里由ServletContext改为ServletRequest
2.ServletRequestAttributeListener接口
和ServletContextListener接口类似的,这里由ServletContext改为ServletRequest
1.新建类继承Thread,
2.把此类交给spring管理
<bean id="b" class="" init-method="start" />
当系统启动时就可以了
var url = window.location.href;
新建一个java类,实现
ServletContextListener
接口,在web.xml中配置
<listener>
<listener-class>类的完全限定名</listener-class>
</listener>
方法1.例如:
StringBuffer sql = new StringBuffer();
sql.append("from Book b where 1=1 ");
if(!"".equals(sum)&&sum!=null){
sql.append(" and b.sum ='"+sum+"'");
}
if(!"".equals(aut)&&aut!=null){
sql.append(" and b.author ='"+aut+"'");
}
if(!"".equals(pub)&&pub!=null){
sql.append(" and b.publish ='"+pub+"'");
}
if(!"".equals(rfid)&&rfid!=null){
sql.append(" and b.addRfidSum ='"+rfid+"'");
}
方法2.
StringBuffer sql = new StringBuffer();
sql.append("from Book b where ");
if(!"".equals(sum)&&sum!=null){
sql.append(" b.sum ='"+sum+"' and ");
}
if(!"".equals(aut)&&aut!=null){
sql.append(" b.author ='"+aut+"' and ");
}
if(!"".equals(pub)&&pub!=null){
sql.append(" b.publish ='"+pub+"' and ");
}
if(!"".equals(rfid)&&rfid!=null){
sql.append(" b.addRfidSum ='"+rfid+"' and ");
}
String s = sql.toString();
s=s.substring(0,s.lastIndexOf(" and ")>0? s.lastIndexOf(" and "):s.indexOf("where"));
System.out.println(s);
当心在单引号和双引号中间不要有空格,不然会出错
WebContext context = WebContextManager.get();
HttpSession session = context.getSession();
ServletContext application = context.getServletContext();
context.getRequest();
context.getResponse();
String s = "2012-08-25";
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd");
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy年M月d日");
try {
System.out.println(sdf2.format(sdf1.parse(s)));
} catch (ParseException e) {
e.printStackTrace();
}
根据有道的API 先根据IP确定城市 在根据城市获取天气
在命令行框中输入tomcat路径,例如
D:\tomcat-6.0.18\bin\service.bat install,在系统服务中找到tomcat,定义为自动启动就好了
在使用ExtJS时,我们往往需要在使用之前加入这么一句:
Ext.BLANK_IMAGE_URL = "....."其中省略部分为s.gif在extjs包中的路径。
那么ExtJS为什么要设置这样一个变量呢?如果我们不这样做会带来什么后果?
首先说后果:
如果没有以上那句代码,Ext会按照默认的地址:http://www.extjs.com/s.gif去下载这张图片,由于网络不通或者速度较慢等原因,可能导致这张图片加载不成功,造成页面上很多小白条。
设置这个变量的原因:
原来ExtJS中在创建组件的时候,组件中需要替换图标的地方,初始化时都是拿这个s.gif替代的,如果用户指定icon属性,它会将s.gif替换为icon的地址,说白了,s.gif就是一个占位的功能。
另外,如果看过ExtJS的源代码可能发现,它对于ie和air的默认实现是去url请求这张图片,而对于其它浏览器则直接使用图片解码,这是因为ie和air不支持图片解码。
----------------------------------------------------------------------------------------------------------
Ext.BLANK_IMAGE_URL
图片位置默认指向:
/resources/images/default/s.gif'
最近在看Ext中jack的window导航式例时,看到一个细节,让我顿时明白了作者的这一做法的初衷。
作者在对一些需要应用图片或者图标的地方,都没有显式写明要应用的图标(片)路径,
而都是通过css来配置,许多应用图标的地方刚开始都Ext.BLANK_IMAGE_URL来替代,
而在css在加载之后就会替换到真实的图标路径 。
这一招就彻底解决了界面的换肤问题。
把extjs源代码包发到wabapps中,启动tomcat,在浏览器地址栏输入
http://localhost:8080/ext/docs/index.html就可以了
简单工厂模式存在的目的是定义一个用于创建对象的接口,此模式由三个部分组成:
(1)工厂类角色:这是本模式的核心,含有一定的逻辑和判断,由一个具体类实现
(2)抽象产品角色:一般是具体产品继承的父类或者实现的接口,
(3)工厂类所创建的对象就是此角色的实例
.properties文件中的数据是键值对形式的,key = value格式,把此文件放在紧跟在src目录下,新建一个类来读取数据,例如:
public class ReadCommand {
/**
* 读取properties文件
*/
private static ReadCommand readConfig = new ReadCommand();
public static Map<String, String> nodeMap = new HashMap<String, String>();
static{
System.out.println("ReadConfig...");
InputStream in = ReadCommand.class.getClassLoader().getResourceAsStream("light_command.properties");
Properties prop = new Properties();
try {
prop.load(in);
Enumeration en = prop.propertyNames();
while(en.hasMoreElements()){
String key = (String) en.nextElement();
String value = (String) prop.get(key);
nodeMap.put(key, value);
}
} catch (IOException e) {
e.printStackTrace();
}
}
//私有化构造函数
private ReadCommand(){}
/**
* 实例化该类(单例)
* * */
public static ReadCommand getInstance(){
return readConfig;
}
/**
* 获取配置的节点的信息
*
* */
public Map<String, String> getNodes(){
return nodeMap;
}
public static Map<String,String> getLightName(){
Map<String, String> map = ReadConfig.getInstance().getNodes();
return map;
}
Map<String,String> map = GetLightName.getLightName();
Set<String> keys = map.keySet();//得到键值
for(String key : keys){
System.out.println(key+"-----"+map.get(key));
}
}
Ext.ux.LightTabPanel.superclass.constructor.call(this, {
id : this.panelId,
title : this.treeNode.text,
layout : 'border',
closable : true,
autoScroll : true,
width: '100%',
height: '100%',
html: '<iframe width=100% height=100% src="
http://192.168.1.5:8080/ord?file:^html/access/employee.htm" />'
});
在面板的构造方法中这样写,就可以了
var alarmTask = {
run : function() {
Ext.Ajax.request(写需要请求的代码);
},
interval : 5000
};
Ext.TaskMgr.start(alarmTask);
List<String> a = new ArrayList<String>();
a.add("6");
a.add("3");
a.add("4");
a.add("1");
a.add("1");
a.add("2");
a.add("2");
a.add("3");
a.add("4");
a.add("5");
a.add("6");
a.add("5");
List<String> b = new ArrayList<String>();
for(String c : a){
if(!b.contains(c)){
b.add(c);
}
}
在删除集合中重复的数据时,只要先创建一个新的集合存放数据就好
用BeanNameAutoProxyCreator自动创建事务代理
下面介绍一种优秀的事务代理配置策略:采用这种配置策略,完全可以避免增量式配置,所有的事务代理由系统自动创建。容器中的目标bean自动消失,避免需要使用嵌套bean来保证目标bean不可被访问。
这种配置方式依赖于Spring提供的bean后处理器,该后处理器用于为每个bean自动创建代理,此处的代理不仅可以是事务代理,也可以是任意的代理,只需要有合适的拦截器即可。这些是AOP框架的概念读者只需了解这种事务代理的配置方式即可。
下面是采用BeanNameAutoProxyCreator配置事务代理的配置文件:
<?xml version="1.0" encoding="gb2312"?>
<!-- Spring配置文件的文件头,包含DTD等信息-->
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"
[url]http://www.springframework.org/dtd/spring-beans.dtd[/url]">
<beans>
<!--定义数据源-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<!-- 定义数据库驱动-->
<property name="driverClassName"><value>com.mysql.jdbc.Driver</value></property>
<!-- 定义数据库url-->
<property name="url"><value>jdbc:mysql://localhost:3306/spring</value></property>
<!-- 定义数据库用户名-->
<property name="username"><value>root</value></property>
<!-- 定义数据库密码-->
<property name="password"><value>32147</value></property>
</bean>
<!--定义一个hibernate的SessionFactory-->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<!-- 定义SessionFactory必须注入DataSource-->
<property name="dataSource"><ref local="dataSource"/></property>
<property name="mappingResources">
<list>
<!--以下用来列出所有的PO映射文件-->
<value>Person.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<!--此处用来定义hibernate的SessionFactory的属性:
不同数据库连接,启动时选择create,update,create-drop-->
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
<!-- 定义事务管理器,使用适用于Hibernte的事务管理器-->
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<!-- HibernateTransactionManager bean需要依赖注入一个SessionFactory bean的引用-->
<property name="sessionFactory"><ref local="sessionFactory"/></property>
</bean>
<!-- 配置事务拦截器-->
<bean id="transactionInterceptor"
class="org.springframework.transaction.interceptor.TransactionInterceptor">
<!-- 事务拦截器bean需要依赖注入一个事务管理器 -->
<property name="transactionManager" ref="transactionManager"/>
<property name="transactionAttributes">
<!-- 下面定义事务传播属性-->
<props>
<prop key="insert*">PROPAGATION_REQUIRED</prop>
<prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
<!-- 定义BeanNameAutoProxyCreator,该bean是个bean后处理器,无需被引用,因此没有id属性
这个bean后处理器,根据事务拦截器为目标bean自动创建事务代理
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
指定对满足哪些bean name的bean自动生成业务代理 -->
<property name="beanNames">
<!-- 下面是所有需要自动创建事务代理的bean-->
<list>
<value>personDao</value>
</list>
<!-- 此处可增加其他需要自动创建事务代理的bean-->
</property>
<!-- 下面定义BeanNameAutoProxyCreator所需的事务拦截器-->
<property name="interceptorNames">
<list>
<value>transactionInterceptor</value>
<!-- 此处可增加其他新的Interceptor -->
</list>
</property>
</bean>
<!--定义DAO Bean ,由于BeanNameAutoProxyCreator自动生成事务代理-->
<bean id="personDao" class="lee.PersonDaoHibernate">
<property name="sessionFactory"><ref local="sessionFactory"/></property>
</bean>
</beans>
TranscationInterceptor是一个事务拦截器bean,需要传入一个TransactionManager的引用。配置中使用Spring依赖注入该属性,事务拦截器的事务属性通过transactionAttributes来指定,该属性有props子元素,配置文件中定义了三个事务传播规则:
所有以insert开始的方法,采用PROPAGATION_REQUIRED的事务传播规则。程序抛出MyException异常及其子异常时,自动回滚事务。所有以find开头的方法,采用PROPAGATION_REQUIRED事务传播规则,并且只读。其他方法,则采用PROPAGATION_REQUIRED的事务传播规则。
BeanNameAutoProxyCreator是个根据bean名生成自动代理的代理创建器,该bean通常需要接受两个参数。第一个是beanNames属性,该属性用来设置哪些bean需要自动生成代理。另一个属性是interceptorNames,该属性则指定事务拦截器,自动创建事务代理时,系统会根据这些事务拦截器的属性来生成对应的事务代理。
在ext的js文件中,使用对象的属性时,如果对象的属性是基本数据类型和String时,和对象的属性是引用属性时,例如是别的类名时,可以这样使用:
var typeRecord = new Ext.data.Record.create([ {
name : 'id',
type : 'long'
}, {
name : 'rfid',
type : 'string'
}, {
name : 'addTime',
type : 'string'
}, {
name : 'food',//food是别的类的对象,Food
type : 'AUTO'//定义为这样
}, {
name : 'foodCode',
type : 'string'
}, {
name : 'sum',
type : 'string'
}, {
name : 'deadTime',
type : 'string'
}]);
在使用时,这样,例如:
columns : [ {
header : '编号',
dataIndex : 'id',
width : 60
}, {
header : '卡号',
dataIndex : 'rfid'
}, {
header : '添加时间',
dataIndex : 'addTime'
}, {
header : '食物现库存',
dataIndex : 'sum'
}, {
header : '食物快要过期,剩余天数',
dataIndex : 'deadTime'
}, {
header : '所属食物的常规数量',
dataIndex : 'food',
renderer: function(v){
return v.num;
}
}, {
header : '所属食物的产地',
dataIndex : 'food',//这样就可以去到Food的对象food的address的数据了
renderer: function(v){
return v.address;
}
}, {
header : '所属食物的保质期',
dataIndex : 'food',
renderer: function(v){
return v.limitTime;
}
}, {
header : '所属食物',
dataIndex : 'food',
renderer: function(v){
return v.foodName;
}
} ]
当想让系统启动时就执行的代码,可以有2中方法实现:
1.让一个类实现InitializingBean接口,重写afterPropertiesSet()方法 ,再把这个类交给spring管理,定义为一个bean,这样就可以了
2.在一个类中自己写一个方法,此方法是无参数的,把这个类交给spring管理,定义init-method="自己定义的方法名",这样也可以,这个接触了对spring的依赖
当系统管理时执行的代码可以这样实现:
让一个类实现DisposableBean接口,重写 destroy()方法,再把这个类交给spring管理,
typeGrid.on('rowclick', function(grid, rowIndex, event) {
currRecord = grid.getStore().getAt(rowIndex);
});
typeGrid是数据类表的面板,currRecord 是这一行的对象
Extjs中分页的使用:
在后台查询程序中查询出的数据集合要放在一个辅助类的对象中辅助类要有2个属性,一个放数据总数,一个房数据集合,例如:
public class DirectStore {
private int totalRecords;
private final List<?> results;
public DirectStore(final int totalRecord, final List<?> results) {
super();
this.totalRecords = totalRecord;
this.results = results;
}
public List<?> getResults() {
return this.results;
}
public int getTotalRecord() {
return this.totalRecords;
}
public void setTotalRecord(final int totalRecord) {
this.totalRecords = totalRecord;
}
@Override
public String toString() {
return "{'totalRecords':" + this.totalRecords + ",'results'"
+ this.results + "}";
}
}
把查询出的额数据集合放在对象中
DirectStore store = new DirectStore(recordNumber, list);
在ext的页面中,需要先定义如下:
var typeStore = new Ext.data.DirectStore({
paramOrder : [ 'start', 'limit' ],
baseParams : {
'start' : 0,
'limit' : 20
},
root : 'results',
totalProperty : 'totalRecords',//和DirectStore对象的totalRecords属性一样
idProperty : 'id',
fields : [ 'id', 'name', 'Unit', 'description' ],//集合中存放的对象的属性
directFn : EamDjn.getDepartment
});
typeStore.load();
再在页面下面写:
bbar: new Ext.PagingToolbar({
pageSize: 20,
store : typeStore,
displayInfo: true,
displayMsg: '显示第 {0} 条到 {1} 条记录,一共 {2} 条',
emptyMsg: '没有记录'
})
这样就完成分页了,需要
function tree3(){
var root=new Ext.tree.TreeNode({
id:"root",
href:"http://www.easyjf.com",
hrefTarget:"_blank",
text:"树的根"});
var c1=new Ext.tree.TreeNode({
id:"c1",
href:"http://www.easyjf.com",
hrefTarget:"_blank",
text:"一级子节点1"
});
var c2=new Ext.tree.TreeNode({
id:"c2",
href:"http://www.easyjf.com",
hrefTarget:"_blank",
text:"一级子节点2"
});
var c3=new Ext.tree.TreeNode({
id:"c3",
href:"http://www.easyjf.com",
hrefTarget:"_blank",
text:"二级子节点1"
});
var c4=new Ext.tree.TreeNode({
id:"c4",
href:"http://www.easyjf.com",
hrefTarget:"_blank",
text:"二级子节点2"
});
root.appendChild(c1);
root.appendChild(c2);
c1.appendChild(c3);
c2.appendChild(c4);
var tree=new Ext.tree.TreePanel({
renderTo:"hello",
root:root,
width:200
});
root.on("click",function(node,event){
alert("您点击了"+node.text);
}
);
c1.on("click",function(node,event){
alert("您点击了"+node.text);
}
);
c2.on("click",function(node,event){
alert("您点击了"+node.text);
}
);
c3.on("click",function(node,event){
alert("您点击了"+node.text);
}
);
c4.on("click",function(node,event){
alert("您点击了"+node.text);
}
);
}
摘要: <html> <head> <link rel="stylesheet" type="text/css" href="ext-3.3.1\resources\css/ext-all.css" /> &nbs...
阅读全文
在tomcat的conf文件夹中的server.xml文件中找到<Connector>节点,在节点中写上URIEncoding="UTF-8",就可以解决整个项目中的get请求的中文乱码
detachedCriteria.add(Restrictions.eq("user.userId", userId));
Restrictions.eq()是等于,Restrictions.allMap()使用Map,使用key和value进行多个等于的对比
Restrictions.gt()大于,Restrictions.ge()大于等于,Restrictions.lt()小于,
Restrictions.le()小于等于,Restrictions.between()对应sql中的between字句,
Restrictions.like()对应sql的like字句,
Restrictions.in()对应sql的in字句
Restrictions.and()
Restrictions.or()
Restrictions.sqlRestnction(),是对sql限定查询
1. String s = “中文”;
S = new String(s.getBytes(“ISO8859-1”),”utf-9”);
2. 使用过滤器:
public class CharsetFilter implements Filter{
private String encoding = "UTF-8";
public void destroy() {
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
request.setCharacterEncoding(encoding);
chain.doFilter(request, response);
}
public void init(FilterConfig filterConfig) throws ServletException {
String encoding = filterConfig.getInitParameter("encoding");
if(encoding != null) {
this.encoding = encoding;
}
}
}
3.request.setCharacterEncoding(“utf-8”);
找到自己的myeclipse安装目录,找到文件
myeclipse.ini,改最后三项数据
-Xmx1024m
-XX:MaxPermSize=1024
-XX:ReservedCodeCacheSize=512m,再重做tomcat就好了
在applicationContext.xml里写:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
">
<!-- 使用注解支持事务
<tx:annotation-driven transaction-manager="transactionManager" /> -->
<!-- 添加jdbc的任务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置事务通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- name表示以什么开始的方法名,比如 add*表示add开头的方法
propagation表示事务传播属性,不写默认有
-->
<tx:method name="save*" propagation="REQUIRED"/>
<tx:method name="del*" />
<tx:method name="update*"/>
<tx:method name="find*" read-only="true"/>
</tx:attributes>
</tx:advice>
<!-- 配置事务切面 -->
<aop:config>
<aop:pointcut expression="execution(* com.yjw.service..*.*(..))" id="pointcut"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"/>
</aop:config>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql:///mydb"/>
<property name="properties">
<props>
<prop key="user">root</prop>
<prop key="password">root</prop>
</props>
</property>
</bean>
<bean id="simpleJdbcTemplate" class="org.springframework.jdbc.core.simple.SimpleJdbcTemplate">
<constructor-arg ref="dataSource"></constructor-arg>
</bean>
<!-- 在使用事务时不能配置jdbc模板,只能配置数据流 -->
<bean id="userdao" class="com.yjw.dao.UserDao">
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean id="userService" class="com.yjw.service.UserService">
<!-- name的值只和set方法后面的有关,要一样 -->
<property name="dao" ref="userdao"></property>
</bean>
</beans>
在service里写:
public class UserService {
private UserDao userdao;
public void setDao(UserDao userdao) {
this.userdao = userdao;
}
public void save(User user){
userdao.save(user);
if(true){
throw new RuntimeException();
}
userdao.save(user);
}
//只读,会使性能提高,推荐使用
//@Transactional(readOnly=true)
public User findById(int id){
return userdao.findById(id);
}
}
在applicationContext.xml里写:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
">
<!-- 使用注解支持事务 -->
<tx:annotation-driven transaction-manager="transactionManager" />
<!-- 添加jdbc的任务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql:///mydb"/>
<property name="properties">
<props>
<prop key="user">root</prop>
<prop key="password">root</prop>
</props>
</property>
</bean>
<bean id="simpleJdbcTemplate" class="org.springframework.jdbc.core.simple.SimpleJdbcTemplate">
<constructor-arg ref="dataSource"></constructor-arg>
</bean>
<!-- 在使用事务时不能配置jdbc模板,只能配置数据流 -->
<bean id="userdao" class="com.yjw.dao.UserDao">
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean id="userService" class="com.yjw.service.UserService">
<!-- name的值只和set方法后面的有关,要一样 -->
<property name="dao" ref="userdao"></property>
</bean>
</beans>在service里加:
//在类的头上加上这个注解,代表这个类的所有方法都加上了事务,
//作用是某个方法里的代码要么都执行,要么都不执行
//默认是在发生RunTimeException是才回滚,发生Exception不回滚
//加上(rollbackFor=Exception.class)表示所有的异常都回滚
@Transactional(rollbackFor=Exception.class)
public class UserService {
private UserDao userdao;
public void setDao(UserDao userdao) {
this.userdao = userdao;
}
public void save(User user){
userdao.save(user);
}
//只读,会使性能提高,推荐使用
@Transactional(readOnly=true)
public User findById(int id){
return userdao.findById(id);
}
}
摘要: Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->在applicationContext.xml文件里写:<?xml version="1.0" encoding="UTF-8"?><beans xmlns...
阅读全文
1,添加jar包struts2-json-plugin-2.3.1.2.jar
2.在json-struts.xml里配置
<package name="myjson" extends="json-default">
<action name="myjson" class="com.yjw.web.MyjsonAction">
<result type="json">
<!--找到根节点-->
<param name="root">user</param>
<!--浏览器不要缓存-->
<param name="noCache">true</param>
<!--GZIP网页压缩协议,可以让传送更快,省流量-->
<param name="enableGZIP">true</param>
<!--排除action里是null的属性-->
<param name="excludeNullProperties">true</param>
</result>
</action>
</package>
在MyjsonAction里写:
package com.yjw.web;
import com.opensymphony.xwork2.Action;
public class MyjsonAction implements Action {
private User user;
private String x;
public String execute() throws Exception {
user = new User();
user.setId(1);
user.setMoney(22);
user.setName("tom");
return "success";
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public String getX() {
return x;
}
public void setX(String x) {
this.x = x;
}
}
在struts2.Xml中写:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.1.7//EN"
"http://struts.apache.org/dtds/struts-2.1.7.dtd">
<struts>
<package name="myxml" extends="struts-default">
<!-- 输出xml的方法不写result -->
<action name="xml" class="com.yjw.web.MyxmlAction"></action>
</package>
</struts>
在action中写:
package com.yjw.web;
import java.io.PrintWriter;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.Action;
public class MyxmlAction implements Action{
public String execute() throws Exception {
HttpServletResponse response = ServletActionContext.getResponse();
response.setContentType("text/xml;charset=UTF-8");
PrintWriter out = response.getWriter();
out.print("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
out.print("<root>");
for(int i=0;i<5;i++){
out.print("<person>");
out.print("<name>person"+i+"</name>");
out.print("</person>");
}
out.print("</root>");
//一定要返回null
return null;
}
}
在jsp里写:
<body>
<input type="button" value="xml" id="btnxml"/>
<div id="mydiv"></div>
<script type="text/javascript" src=js/jquery-1.5.1.min.js></script>
<script type="text/javascript">
$(document).ready(function(){
$("#btnxml").click(function(){
$.get("xml.action",function(xml){
$(xml).find("person").each(function(){
var name = $(this).find("name").text();
$("#mydiv").html($("#mydiv").html()+name+'<br/>');
});
});
});
});
</script>
</body>
在jsp里写:
<a href="download.action">点此下载文件</a>
在struts.xml中:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.1.7//EN"
"http://struts.apache.org/dtds/struts-2.1.7.dtd">
<struts>
<package name="mydown" extends="struts-default">
<action name="download" class="com.yjw.web.DownAction">
<param name="id">1</param>
<result type="stream">
<!-- 下载文件的mime类型 -->
<param name="contentType">${fileType}</param>
<!-- 下载文件的描述 -->
<param name="contentDisposition">attachment;filename=${fileName}</param>
<!-- 设置缓冲区大小 -->
<param name="bufferSize">1024</param>
<!-- 获得文件名的getxxx方法的名字 ,不包含get-->
<param name="inputName">inputStream</param>
</result>
</action>
</package>
</struts>
在action中的程序:
package com.yjw.web;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.Action;
public class DownAction implements Action{
private String fileName;
private String id;
private String fileType;
public String execute() throws Exception {
return "success";
}
public InputStream getInputStream() throws IOException{
String path = ServletActionContext.getServletContext().getRealPath("/");
if(id.equals("1")) {
path = path + "download/less.pdf";
fileName = "css.pdf";
fileType = "application/pdf";
} else {
path = path + "download/data.xlsx";
fileName = "data.xlsx";
fileType = "application/vnd.ms-excel";
}
FileInputStream stream = new FileInputStream(new File(path));
return stream;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getFileType() {
return fileType;
}
public void setFileType(String fileType) {
this.fileType = fileType;
}
}
HSSFWorkbook wb = new HSSFWorkbook();
FileOutputStream fileout = new FileOutputStream("d:/b.xls");
wb.write(fileout);
fileout.close();
验证码:
1, 导入jar包jcaptcha验证码
2.在web.xml里配置<servlet>
<servlet-name>j</servlet-name>
<servlet-class>com.octo.captcha.module.servlet.image.SimpleImageCaptchaServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>j</servlet-name>
<url-pattern>/jcaptcha.jpg</url-pattern>
</servlet-mapping>
3.在页面上写
<form action="vali.action" method="post">
<input type="text" name="name"/>
<a href="javascript:void(0)"
id="mya"><img src="jcaptcha.jpg" id="myimg"/></a>
<input type="submit" value="save"/>
</form>
<script type="text/javascript" src=js/jquery-1.5.1.min.js></script>
<script type="text/javascript">
$(document).ready(function(){
$("#mya").click(function(){
$("#myimg").attr("src","jcaptcha.jpg?xxx=" + Math.random());
});
4.在struts-vali.xml里写
<?xml version="1.0"
encoding="UTF-8"?>
<!DOCTYPE struts
PUBLIC
"-//Apache Software Foundation//DTD Struts
Configuration 2.1.7//EN"
"http://struts.apache.org/dtds/struts-2.1.7.dtd">
<struts>
<package name="myvali"
extends="struts-default">
<action name="vali" class="com.yjw.web.ValiAction">
<result>WEB-INF/views/list.jsp</result>
<result name="error">WEB-INF/views/main.jsp?id=1</result>
</action>
</package>
</struts>
5.在ValiAction里写:
package com.yjw.web;
import org.apache.struts2.ServletActionContext;
import
com.octo.captcha.module.servlet.image.SimpleImageCaptchaServlet;
import com.opensymphony.xwork2.Action;
public class ValiAction implements Action{
private String name;
public String execute() throws Exception {
boolean result = SimpleImageCaptchaServlet.validateResponse(ServletActionContext.getRequest(),
name);
System.out.println(result);
if(result){
return "success";
}else {
return "error";
}
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
在javaIO中,文件的查询和删除,文件的复制程序如下:
普通的复制是:
public class Acopy {
public void copy(String oldpath,String newpath ) throws IOException {
File of = new File(oldpath);
File nf = new File(newpath);
if(!nf.exists()){
nf.createNewFile();
}
FileInputStream i = new FileInputStream(of);
FileOutputStream o = new FileOutputStream(nf);
int b= 0;
byte[] buffer = new byte[100];
while((b=i.read(buffer))!=-1){
o.write(buffer, 0, b-1);
}
i.close();
o.flush();
o.close();
}
}
加强的复制是:
public class Bcopy {
public void copy(String opath,String npath) throws IOException{
File of = new File(opath);
File nf = new File(npath);
if(!nf.exists()){
nf.createNewFile();
}
FileInputStream i = new FileInputStream(of);
BufferedInputStream bi = new BufferedInputStream(i);
FileOutputStream o = new FileOutputStream(nf);
BufferedOutputStream bo = new BufferedOutputStream(o);
int b = 0;
byte[] buffer = new byte[100];
while((b=bi.read(buffer))!=-1){
bo.write(buffer, 0, b-1);
}
bi.close();
bo.flush();
bo.close();
}
}
文件的查询是:
public void show(String path){
File f = new File(path);
if(f.isFile()){
System.out.println(f.getPath());
}else if(f.isDirectory()){
File[] files = f.listFiles();
if(files!=null){
for(File file : files){
if(file.isFile()){
System.out.println(file.getPath());
}else if(file.isDirectory()){
System.out.println("["+file.getPath()+"]");
show(file.getPath());
}
}
}
}
}
文件的删除是:
public void del(String path){
File f = new File(path);
if(f.isFile()){
f.delete();
}else if(f.isDirectory()){
File[] files = f.listFiles();
if(files.length==0){
f.delete();
}else if(files!=null){
for(File file : files){
if(file.isFile()){
file.delete();
}else if(file.isDirectory()){
del(file.getPath());
}
}
}
}
f.delete();
}
在建立线程时,有两种方式,1是继承java.lang.Thread类,重写run方法,此方法用于你想让线程干的事,在调用此方法时,不能直接调用run方法,要调用start方法,如果想访问此线程,使用Thread.currentThread()方法。2,是实现Runnable接口,在调用时,因为接口没有start方法,所以要先创建出实现类的的对象, 再创建出Thread的对象,把实现类的对象传入Thread的对象的构造方法中,再用Thread的对象调用start()方法。
线程有生命周期的,新建 ,就绪,运行,死亡。新建以后只有调用start方法才处于就绪队列,处于就绪队列的线程在获得处理机资源后处于运行,在运行过程中,如果调用sleep方法,或IO阻塞例如Scanner输入,或等待同步锁,或等待通知时就处于阻塞,这是释放处理机资源,在sleep时间到,或IO方法返回,或获得同步锁,或受到通知后,处于就绪队列,线程在run执行完成,或Error,或exeception时,就死亡。可以调用stop方法让线程死亡,但是禁止使用,可以使用isAlive方法判断线程是否死亡,该方法在线程处于就绪,运行,阻塞时返回true,处于新建和死亡时返回false,线程一旦死亡,不能再次调用start方法让线程重新执行。
当一个程序在执行中被另外一个线程插队,并且后来的线程需要先执行完后原来的线程才能执行,就要让插队线程先调用start方法,再调用join方法,进行插队。
守护线程就是在主线程死亡后,守护线程也随之死亡,在使用时让守护线程的对象先调用setDaemon(true)方法,再调用start方法。
当多个线程同时对同一个对象的实例属性进行操作时,会引起线程的同步问题,为了消除线程的同步,可用synchronized来修饰有可能引起线程同步的方法,也可用用synchronized(this)
{方法代码} ,设置同步代码块,在JDK1.5以上的版本可使用同步锁来操作,具体做法是:
Private final ReentrantLock lock = new ReentrantLock();
在方法内部定义lock.lock();在程序执行完毕后,一定要解锁,lock.unlock();