Servlet(Server + Applet):java服务器端小程序
用java编写的服务器端程序,接收用户的请求并作出响应.
阅读JavaEE_6_API帮助文档.chm 中servlet的含义
上面的文档包含了JavaEE的全部技术
也可以查看servlet的独立文档(只包含servlet技术的api)
查api源文档:
This interface defines methods to initialize a servlet, to service requests, and to remove a servlet from the server. These are known as life-cycle methods and are called in the following sequence:
The servlet is constructed, then initialized with the init method.
Any calls from clients to the service method are handled.
The servlet is taken out of service, then destroyed with the destroy method, then garbage collected and finalized.
1)新建web工程
1.起一个web工程名
2.选J2EE1.4版本(高版本的多了个EJB,目前不需要,所以不选高版本)
Web工程的目录结构
ShanshiWeb(Web工程名)
--src(java源文件)
--WebRoot(web应用程序)
--页面文件(html、jsp...)
--WEB-INF
--lib(jar包放到这,比如ojdbc6.jar)
--classes(java字节码文件)
--web.xml(web部署描述符文件 用来配置web应用程序的信息)
2)如何编写第一个servlet?
需求:服务器向客户端输出 Hello,Servlet!!!
总共分三步
1.导包
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
2.继承HttpServlet 抽象类 重写doGet() 和doPost();
public class HelloServlet extends HttpServlet{
@Override
public void doGet(HttpServletRequest request,HttpServletResponse response)
throws IOException,ServletException{
PrintWriter out = response.getWriter();
out.println("Hello,Servlet!!!");
out.flush();
out.close();
}
@Override
public void doPost(HttpServletRequest request,HttpServletResponse response)
throws IOException,ServletException{
this.doGet(request, response);
}
}
3.在web.xml配置Servlet
servlet配置如下
HelloWorldServlet
class>com.servlet.HelloWorldServlet class>
HelloWorldServlet
/HelloWorldServlet
3)如何运行第一个Servlet?
运行普通的java程序,需要JRE就可以了,运行jsp/servlet程序,需要web服务器.
常用的Web服务器
1.tomcat (apache 开源 免费) 准确的说叫JSP/Servlet容器
2.jboss(开源 红帽)
3.WebSphere(IBM 支持J2EE的13个规范)
4.WebLogic(BEA 被oracle收购了 用的最多 支持J2EE规范 的13个技术规范)
5.GlassFish(sun公司 被oracle收购了)
6.resin…
7.jetty
…
我们使用tomcat
前提:配置web服务器
1.去官方网站下载 http://tomcat.apache.org/
有安装版的,有绿色版的,建议下载绿色版!!!
2.直接把tomcat解压缩到一个目录下就ok了
注意不要放到带中文或带空格的路径下,比如Program Files
如果想在MyEclipse下使用Tomcat,需要在MyEclipse配置一下
Windows-Preferences–MyEclipse–Servers
–tomcat—tomcat6.x 选中tomcat服务器根目录后 点击Enable
然后apply and ok就可以了
Web应用程序 放到web服务器上(tomcat)
(1)手工部署
把WebRoot文件夹拷贝到了 tomcat 下webapps里,并且把WebRoot更名为和Web Project名一样的名字
(2)使用MyEclipse工具部署
底层做了什么?
把WebRoot文件夹拷贝到了 tomcat 下webapps里,并且把WebRoot更名为和Web Project名一样的名字,相当于手工部署,只不过更加方便.
必须配置JAVA_HOME
因为tomcat是java写的程序,依赖JRE, 不配置JAVA_HOME, tomcat启动时一闪而过
(1)使用MyEclipse工具
(2)在控制台下使用s tartup.bat命令
如果在控制台下敲命令启动还需要配置其他两个环境变量
PATH 加入D:\apache-tomcat-8.0.23\bin;以前的内容
CATALINA_HOME=D:\apache-tomcat-8.0.23
告诉startup.bat这个启动程序tomcat在哪里?
使用两个tomcat演示
建议不配置CATALINA_HOME和PATH,这样点哪个tomcat的startup.bat就是启动哪个
shutdown.bat 关闭tomcat
在浏览器中输入
http://localhost:8080/HuangHuaiMiddle/HelloServlet
http://tomcat服务器的ip地址:端口号/Web应用程序名/页面名或Servlet名
另:默认访问欢迎页面 在web.xml 里面配置
file-list>
file>index.jsp file>
file-list>
补充:Servlet3(使用注解配置Servlet)
注意: 如果想使用Servlet3必须注意如下两步
1.创建工程的时候 选JavaEE6规范
2.Tomcat要使用7.0+(含7.0)
@WebServlet(name=”HelloServlet”,urlPatterns={“/aaa”,”/bbb”})
public class HelloServlet extends HttpServlet {
}
或
@WebServlet(“/abc”)
public class HelloServlet extends HttpServlet {
}
tomcat6:
tomcat-users.xml
在tomcat-users>前面加入下面两句话保存后,重启tomcat即可
<role rolename="manager"/>
<user username="tomcat" password="tomcat" roles="manager"/>
tomcat7\8:
tomcat-users.xml
在tomcat-users>前面加入下面两句话保存后,重启tomcat即可
<role rolename="manager-gui"/>
<user username="tomcat" password="tomcat" roles="manager-gui"/>
编译HelloServlet.java时找不到依赖的类,因为javac默认把j2se 的jar包添加到classpath下,
其他的jar包,需要手工添加,所以必须把servlet-api.jar添加到classpath下
CLASSPATH=.;C:\Program Files\Java\jdk1.8.0_31\lib;D:\apache-tomcat-6.0.44\lib\servlet-api.jar
经常出现的错误之404—-页面没找到
页面没找到或请求的Servlet不存在
经常出现的错误之500—-服务器内部错误
自己写的Servlet代码错误,具体错误看报错描述,看自己写的代码的第一行。
1.running模式(运行模式)
2.debug模式(调试模式)
debug模式 会帮你重新部署和加载
区别1:
Running模式不能进行断点调试,debug模式 可以进行断点调试
区别2:
Running模式类和配置文件变了以后 只会从新部署、不会从新加载类和配置文件
Debug模式 类和配置文件变了以后 会从新部署、从新加载
小技巧1
如果想查看是否重新部署了,去webapps/web应用/WEB-INF/classes 用反编译工具看一下
但是重新部署 只是 硬盘上修改了 我们真正访问的 是 内存中的对象
小技巧2:
如果没有帮你从新加载 可以在web.xml 打两个空格 工具会帮你从新加载 相当于重启了服务器 不要随便重启服务器
因为实际工作中 一重启服务器 可能要1分钟多钟
看到这个界面证明服务器已经从新加载了类文件,这样再访问就是更改后的类了
补充:配置servlet url-pattern时一定不能配置成/和*.jsp
/
/ 为缺省的servlet,即当请求的servlet都没有匹配上时,使用缺省的servlet处理
参见tomcat\conf\web.xml
default
org.apache.catalina.servlets.DefaultServlet
default
/
如果用户自己在项目下的web.xm中也配置一个 url-pattern为/的servlet,这样会把tomcat默认提供的缺省的servlet给覆盖掉,这样当访问的资源(jsp或servlet)不存在时,就不会给你提供404的错误提示了.
*.jsp同理
相对路径问题
为什么有乱码
编码和解码方式不一致
编码: 把看的懂得明文转换成看不懂的密文.
解码: 把看不懂的密文转换成看的懂的明文.
解决方法:
response.setContentType(“text/html;charset=utf-8”);
作用:一.设置服务器响应类型 服务器向客户端产生一个文本或html文件
二.charset=utf-8的作用
1.设置服务器响应的编码方式(即生成的html页面的编码方式)
2.提示浏览器使用该编码方式 解码
解决方法:
1.method=”post”时,在servlet中加入request.setCharacterEncoding(“utf-8”);//提示tomcat使用utf-8解码发过来的数据
2.tomcat6及之前,上述解决方法只对post方式有效,tomcat6之后,method=”get”的方式就不用修改了,服务器默认get也用post的方式处理。
tomcat6,如果method=”get”时,需要修改tomcat\conf\server.xml 的71行,加入URIEncoding=”utf-8”即可。
7.0以上不用修改。
1.Servlet的最初目的
以前最初servlet 是用来动态产生html页面(时间、用户名) 但是这样很麻烦
演示代码
PrintWriter out = response.getWriter();
out.println("");
out.println("");
out.println("测试 ");
out.println("");
out.println("");
out.println("当前时间:" + new Date());
out.println("");
out.println("");
out.flush();
out.close();
这样写非常繁琐,不太好!
所以为了简化Servlet输出,有了JSP(Java Server Pages)
演示代码 test.jsp
<body>
<%=new Date() %>
body>
1.Servlet的现在用途
当做控制器
相当于项目经理
职责: 起控制和调配大局的作用
1.填充数据(接收客户端请求)
2.调用业务逻辑 (添加商品种类)
3.转发视图(jsp)
model1= jsp + javabean (已被淘汰)
model2 = jsp + javabean + servlet
model2模型更符合MVC设计模式,符合OCP原则,符合高内聚,低耦合的设计。
盖一个楼
架构模式(考虑整体 一栋楼的整体轮廓 架子 如何搭起来 考虑宏观)
设计模式(考虑局部)
1.户型如何设计(两室一厅、三室一厅) 2.暖气管道怎么布置 3.墙体保温层如何设计
一.M Model 模型
javabean
(1)业务模型 Service+Dao
(2)数据模型 VO
二.V View 视图
JSP 向客户端显示信息
三.C Controller 控制器 Servlet
1.填充数据
2.调用业务逻辑
3.转发视图jsp
model2=jsp(V)+javabean(M)+servlet(C)
三层架构
持久层:DAO+VO(实体类) 功能把数据持久化(保存)到数据库
业务层:Service
表现层:Controller + JSP
初学者容易犯的错 直接把业务逻辑代码 写到 控制器中
如果把业务逻辑直接写到控制器中,相当于项目经理直接干底层的活,这种写法叫 “强大”的servlet
创建servlet时机有两个
1.第一次访问Servlet的时候创建(演示servlet生命周期)
1.类加载
2.实例化一个servlet 创建Servlet对象
以前调用方法是程序员在main方法中主动调用的
public static void main(String[] args){
HelloServlet hs = new HelloServlet();
hs.doPost();
}
现在为什么没有创建对象和调用方法 该方法也能执行呢?
是因为现在的创建对象和调用方法 都是tomcat容器(jsp/servlet容器)帮你完成的
3.init方法
做一些初始化工作..比如从web.xml文件中读取配置信息
4.service方法 //用来处理客户端请求 判断请求类型get 调用doGet,post 调用doPost 在该方法中完成
tomcat会为每一个客户端创建一个单独的线程 在该线程中调用service()方法为客户端服务
if(客户端请求是post){
this.doPost(request,response);
}else if(get请求){
this.doGet(request,response);
}
5.destroy方法 (销毁方法)
程序员能主动调用destroy方法来销毁servlet对象吗?
不能,这些方法都是tomcat容器调用的
destroy方法 什么时候会被调用
(1)web服务器关闭时
(2) web应用程序关闭时(或被移除时)
(3)如果一个Servlet长时间没有访问 调用destory方法
具体执行策略:会先把对象 保存到文件中(使用对象序列化技术) 等再访问该servlet对象时使用返序列化技术恢复Servlet
这样Servlet的状态就不会被丢失了(比如servlet中的实例变量 就不会被清零了)
6.类卸载
演示代码:
package com.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//演示servlet生命周期
public class LifeCycleServlet extends HttpServlet {
static {
System.out.println("1.LifeCycleServlet类加载");
}
public LifeCycleServlet() {
super();
System.out.println("2.创建了Servlet对象");
}
@Override
public void init(ServletConfig config) throws ServletException {
System.out.println("3.(1)带参数的init方法执行");
super.init(config);
/*String encoding = config.getInitParameter("encoding");
System.out.println(encoding);*/
}
public void init() throws ServletException {
System.out.println("3.(2)不带参数的 init方法被调用");
}
protected void service(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
System.out.println("4.service方法被调用");
}
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
System.out.println("in doGet");
PrintWriter out = response.getWriter();
out.println("hello,servlet!");
out.flush();
out.close();
}
@Override
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
System.out.println("in doPost");
this.doGet(request, response);
}
public void destroy() {
super.destroy();
System.out.println("Servlet对象被销毁");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
重点:只有一个Servlet对象
对于同一个Servlet类的请求 只有一个Servlet对象
相当于每来一个新的请求 容器会为这个新的请求启动一个线程 并且在该线程内调用
service()方法
执行过程:
第一次访问时 先类加载、创建对象、调用init方法初始化、service方法
第二次再访问 前面的都不执行了,直接执行service方法
二. web服务器启动时创建
如果想让servlet启动时就被创建
LifeCycleServlet
com.servlet.LifeCycleServlet
1
十一.如何在servlet里获取web.xml里的初始化参数
在web.xml配置 需求变了 可以不修改代码 符合OCP
1.首先在web.xml配置
LifeCycleServlet
com.servlet.LifeCycleServlet
encoding
utf-8
1
2.然后在servlet的init(ServletConfig config)方法中读取web.xml中的初始化参数
public void init(ServletConfig config) throws ServletException {
super.init(config);
String encoding = config.getInitParameter("encoding");
System.out.println(encoding);
}
1.Servlet接口
2.GenericServlet抽象类 实现了Servlet
3.HttpServlet抽象类 继承了GenericServlet
由于对于同一个Servlet类的请求(比如HelloServlet),只会创建一个Servlet对象。Tomcat
是对于一个客户端的请求,起一个单独的线程处理,在该线程内调用service方法,所以Servlet
有多线程安全问题.
代码演示:
public class UnSafeServlet extends HttpServlet {
private int sum = 0;//共享资源
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
PrintWriter out = response.getWriter();
sum++;
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
out.println(sum);//第一个客户端期望看到1 实际看到的是2
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}
如何解决
1.实现SingleThreadModel
public class UnSafeServlet extends HttpServlet implements SingleThreadModel {
这时候对于一个新的客户端请求,tomcat会为其创建一个新的Servlet对象为它服务,所以不会出现多线程安全问题。
不推荐 100W个用户同时访问 创建了100W个对象 内存溢出
2.同步代码块
不推荐 太慢 一个Servlet执行完 才能执行另外一个
3.不要在Servlet中写实例变量
附:MyEclipse2014 如何修改Servlet模板
默认创建的Servlet带注释,每次创建都需要删除比较麻烦,如何修改Servlet模板
1.找到MyEclipse安装路径下的plugins文件夹
C:\Users\Administrator.USER-20150213PV\AppData\Local\MyEclipse Professional 2014\
Plugins
2.搜索
com.genuitec.eclipse.wizards
3.使用winrar打开后 ,模板文件在templates文件夹下
4.Servlet.java就是Servlet的模板文件,解压出来一份,然后修改完模板后,
直接把修改后的文件拖拽到rar里替换以前的Servlet.java文件
5.重启MyEclipse即可