📄 day02.txt
字号:
Servlet_day02 langna 2007-9-24 星期一
回顾:
1, JAVA_HOME
CATALINA_HOME
2, 目录结构:
webapps:(tomcat 的发布目录)
serv-app |- WEB-INF |--classes
|-- web.xml
|- 静态页面
3, servlet, 直接实现Servlet接口,覆盖service方法
实现HttpServlet类,覆盖doGet 或 doPost
不覆盖的话,报405的错误;
如果服务一样在一个里面调用另一个就行;
如果服务不一样的话,分别实现就行;
http://ip:port/应用路径/虚拟路径
4, 生命周期:
创建loading; 由服务器创建的;
初始化;init();
服务方法;service();doGet();doPost();
销毁:destroy();
把 servlet 放到 servlet容器里, 替你管理 ;都有自己的生命周期;
不一定是关闭服务器时才销毁, 规范没有规定死;
正常情况下一定会调用destroy方法;特殊情况下(如 掉电)不调;
释放一些线程,关闭一些文件;但不能过分依赖;
一, servlet的生命周期:
1, servlet的创建时机:
1)第一个请求来的时候,判断servlet实例是否存在,不存在的话创建一个实例;
启动服务器是没有servlet实例被创建的; 这是默认的;
2)在配置文件web.xml的<servlet>标签中;
<load-on-startup>正数</load-on-startup>,表示服务器启动时创建,并依照数字大小按顺序创建,
只用重要的Servlet才会是用这个设置。1, 2 , 3 ; 1先被创建;但不要相互依赖;
为什么服务器启动时创建:
如:发现文件不存在的业务, 启动服务器时看,不能等第一个请求到来时才发现;
或者是解析xml文件是否合法时;这些业务逻辑放在init()方法中;不存在时可以抛异常;
凡是对外界有依赖时或者重要的复杂的servlet , 用这种初始化方法;
Tomcat用的是SAX解析;
如果web.xml 写错了,或不合法的话,应用就会发布失败;连静态页面也不能访问;
打开控制台可以看到出错信息: catalina.sh run
2, init()方法是工作在单线程情况下的;
log.txt 记录访问用户的ip地址:
log.txt文件放到哪里? 绝对路径;c:\ 或 /home/soft 都不跨平台;
跨平台: 不改 .java源文件 , 不改xml文件 或 属性文件;
一般只能满足第一个要求; 把 xml 文件再配置一下;
servlet 初始化参数在<servlet>标签中配置 : 可以用ServletConfig对象的
getInitParameter(String name)方法来得到参数。
<init-param>
<param-name>file</param-name>
<param-value>c:\log.txt</param-value>
</init-param>
public void init(ServletConfig config)throws ServletException{
this.config = config;
init();
}
FileOutputStream;
没有文件会给你创建,但是没有目录不会给你创建;
如果doGet方法什么也不写,会返回一个空白页面给你;
成员变量和局部变量最好不起同一个名字;
//写日志:
logger.print(new Date()+" : ");
logger.print(request.getRemoteAddr());//获取客户端的 ip 地址;
logger.flush();
getServletConfig() ;//如果子类没有覆盖的话, 得到父类 servlet 的初始化信息;
500-- 执行servlet代码时报异常;
父类的init(ServletConfig config)方法将config保存下来;而我们那覆盖时没有保存下来;
如果覆盖有参的, 必须在子类中调用 super.init(config);才能通过getServletConfig()得到值;
或者直接覆盖无参的方法,父类中有参的会自动调用无参的;
public void init(ServletConfig config)throws ServletException
{
this.config = config;
init();
}
public void init()throws ServletException
{
.....;//覆盖了的无参的init()方法,会在Servlet创建时调用有参的init方法时
也会被调用。
}
直接调用getInitParameter()方法而不用再通过getServletConfig(); 方法内部实现了调用,节省编程;
一个 <init-param> 标签只能配一个参数; 而 <init-param> 可以配多次;
3, service()方法:
servlet只有一个, 并发时,多个线程同时去执行service方法;
request/response 每个线程一个;
给这几个语句加锁:
synchronized(this/logger){// this是当前的servlet; 或 logger的空间; 在这里是一样的;
logger.print(new Date()+" : ");
logger.print(request.getRemoteAddr());//获取客户端的 ip 地址;
logger.flush();
}
每个对象都是一块内存空间, (属性如果是公共的,要结合final;不能被修改);
getName();//不用考虑并发;
setAge();//必须考虑并发;
getGender();//锁越细越好;对属性加锁;
除非方法体中的所有内容都需要同步,才对方法加锁;否则只对代码块加锁就行了;
response和request每次访问都会创建新的;局部变量; 不会构成并发;
如何编写线程安全的资源(加锁):
1) 首先判断需不需要加锁;
操作同一资源,修改时; 或 有些资源只能工作在单线程下;
一个连接在同一时间只服务于一个线程;
2) 怎么样去加锁;
对于局部(成员变量)的,直接对当前对象加锁即可;(同一时间只有一个servlet );
对于全局的, 直接对静态变量(类名.class)加锁即可;
碰见成员变量,用Vector ; 和实例的数量是一样的;
方法的变量,用ArrayList; 每次调用方法都会创建新的;
servlet 是服务器端的被多个线程同时访问的资源; 不要在service方法体中自己再开一个线程;
ServletConfig : 在init之前已经封装好了, 只有一个;
SingleThreadModel:标记接口; 只解决了实例变量并发的问题;没有解决静态变量的问题;
避免使用实例变量; 避免不了的要加锁;
4, destroy();
工作在单线程下的;
下面的了解;无太大意义;
web这种环境不适合做很长时间的访问;以下情况不用考虑; 长时间执行的内容放在后台执行;
一个线程正在执行init()时,不可能有线程执行service();
有线程执行service()时,有可能有一个线程进入destroy();
在destroy()方法中判断一下,所有进入servlet的线程都正常结束;再执行destroy()方法;
用计数器, 是否关闭服务器; 来实现;
伪代码:
private int threads;
private boolean isShuttingDown;
public synchronized boolean isShuttingDown(){
return isShuttingDown;
}
public synchronized void enterService(){
threads++;
}
public synchronized void leaveService(){
threads--;
notifyAll();
}
public void doPost(){
enterService();
for(int i=0;i<=10;i++){
if(isShuttingDown()){
break; //正常退出;
}
//service
}
leaveService();
}
public void destroy(){
synchronized(this){
if(thread>0){
isShuttingDown=true;
}
while(thread>0){
wait();
}
}
}
二 , Form 表单:
reset :重置, 将页面恢复到打开时的状态;而不是清空;
Enumeration paramNames=request.getParameterNames();
while(paramNames.hasMoreElements()){
String name=(String)paramNames.nextElement();
String[] values = request.getParameterValues(name);
out.println(name+ "= " + values);
}
//连接values
private String join(String str, String[] val){
}
测试:
配置文件: /servlet虚拟路径
action="/应用路径/servlet虚拟路径"
浏览器上, http://ip:端口号/应用路径/servlet虚拟路径
表单:默认发送的有text, password, hidden, textarea;
单选框和复选框必须选才能发过来; 否则是空串;
getParameter(参数名);//返回参数的值, 名字必须一致,包括大小写;如果不存在返回null;
注意复选框的处理;
注意:
数据库不能放到公共网络上; 放到局域网中,必须通过代理服务器来访问;
定时的将数据从一个企业的数据库导出来, 放到另一个企业的数据库中;
1) 备份,还原; 数据库不能直接访问;
2) t表 , m表 , jdbc代码处理; 数据库ip地址不能公开;
3)客户端,服务器端, 写一个定时器, 用socket传送, 封装 xml , 解析xml 用jdbc ;
getParameterMap: key -- String
value-- String[]
超链接和在地址栏传参数(查询字符串)一样; 都是get请求;
传大量的信息或保密的信息用post请求;
下次课:
解析请求和解析请求的url;
如何用jdbc;
如何配连接池;
问题:
1, 如何编写线程安全的servlet;
2,如何解析请求;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -