servlet本身就是一种java类,这种java类可以提供web形式的访问(Java EE 规范)
关键字 | 作用 | 说明 |
---|---|---|
Servlet | 接口 | 有五个抽象方法 |
GenericServlet | 抽象类 | 有一个抽象方法 |
HttpServlet | 抽象类 | 没有抽象方法 |
HttpServlet-继承->GenericServlet-实现->Servlet接口
第一种方式:
写一个类去实现接口servlet
最重要的是实现接口中的service方法
这个方法就是我们在访问servlet的时候被tomcat服务器调用的
第二种方式:
写一个类去继承父类GenericServlet
抽象类GenericServlet里面有一个抽象方法service,这个方法是servlet接口中的方法,所以GenericServlet只实现了Servlet接口中的四个抽象方法,还剩下这个service没有实现。同时,GenericServlet类中不但实现了Servlet接口中的init方法,而且还重载了一个无参的init()方法
源代码中两个init方法的实现:
//tomcat服务器默认调用的是这个init方法
@Override
public void init(ServletConfig config) throws ServletException {
this.config = config;
this.init();
}
//用户需要重写的是这个init()方法
public void init() throws ServletException{
// NOOP by default
}
第三种方式:
写一个类去继承父类HttpServlet
HttpServlet是一个抽象类,但是没有任何抽象方法
HttpServlet类中自定义了很多doXxxx方法,每一种方法都对应了浏览器发送请求的方法,一般常用的浏览器发请求方式为get和post,这两种方式分别对应了这个类中的doGet方法和doPost方法。
HttpServlet类中,有两个service方法
//这个service方法Servlet接口中的
void service(ServletRequest req, ServletResponse res){...}
//这个service是HttpServlet中重载的方法
void service(HttpServletRequest req, HttpServletResponse resp){...}
源代码中俩个service方法的实现:
//实现Servlet接口中的service方法
@Override
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
HttpServletRequest request;
HttpServletResponse response;
try {
request = (HttpServletRequest) req;
response = (HttpServletResponse) res;
} catch (ClassCastException e) {
throw new ServletException("non-HTTP request or response");
}
//调用重载之后的service方法
service(request, response);
}
//HttpServlet类中重载的service方法
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String method = req.getMethod();
if (method.equals(METHOD_GET)) {
long lastModified = getLastModified(req);
if (lastModified == -1) {
// servlet doesn't support if-modified-since, no reason
// to go through further expensive logic
doGet(req, resp);
} else {
long ifModifiedSince;
try {
ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
} catch (IllegalArgumentException iae) {
// Invalid date header - proceed as if none was set
ifModifiedSince = -1;
}
if (ifModifiedSince < (lastModified / 1000 * 1000)) {
// If the servlet mod time is later, call doGet()
// Round down to the nearest second for a proper compare
// A ifModifiedSince of -1 will always be less
maybeSetLastModified(resp, lastModified);
doGet(req, resp);
} else {
resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
}
}
} else if (method.equals(METHOD_HEAD)) {
long lastModified = getLastModified(req);
maybeSetLastModified(resp, lastModified);
doHead(req, resp);
} else if (method.equals(METHOD_POST)) {
doPost(req, resp);
} else if (method.equals(METHOD_PUT)) {
doPut(req, resp);
} else if (method.equals(METHOD_DELETE)) {
doDelete(req, resp);
} else if (method.equals(METHOD_OPTIONS)) {
doOptions(req,resp);
} else if (method.equals(METHOD_TRACE)) {
doTrace(req,resp);
} else {
//
// Note that this means NO servlet supports whatever
// method was requested, anywhere on this server.
//
String errMsg = lStrings.getString("http.method_not_implemented");
Object[] errArgs = new Object[1];
errArgs[0] = method;
errMsg = MessageFormat.format(errMsg, errArgs);
resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
}
}
web项目本身就需要在多线程的环境中运行,tomcat服务器会提供这样的多线程环境,当浏览器发送一个请求,tomcat接收到这个请求之后会开启一个线程去处理这个请求
在这种环境下,由于servlet是单例,所以在servlet中声明的成员变量,就会有线程安全的问题。
所以我们应该尽量少的在servlet中定义成员变量
servlet对象是在用户第一次访问它的时候,由tomcat服务器来创建的(可以通过配置进行改变)。
tomcat服务器还会调用servlet里面的init(ServletConfig config),这个有参的init方法会调用无参的init()方法,程序员就可以重写这个无参的init()方法,对创建好的servlet对象进行初始化操作。
那么tomcat服务器会调用这个servlet对象中的service方法,只不过service方法中又进行了方法的层层调用,最后调用到了我们重写的doGet或者是doPost方法
tomcat服务器会调用servlet里面的destory方法,程序员就可以重写这个方法,表示当对象销毁的时候需要做哪些额外的处理
servlet对象被销毁的情况
1.服务器【正常】关闭的时候
2.服务器重新加载web项目的时候(reloading)
只要在
标签中,添加一个子标签
就可以了
标签表示当前这个servlet需要在启动tomcat服务器期间就被创建出来
标签里面需要放一个正整数,数值的大小可以决定servlet对象被创建的先后顺序,数值越小就越先被创建。(如果有多个servlet对象需要在tomcat启动期间被创建的话)
//初始化servlet对象的时候被调用
void init(ServletConfig config)
//销毁servlet对象的时候被调用
void destroy()
//访问servlet对象的时候被调用
void service(ServletRequest req, ServletResponse res)
//返回servlet相关信息,比如作者、版本、版权等
//父类中(GenericServlet)默认返回一个空字符串 ""
//如果需要的话,程序员可以自己重写这个方法
String getServletInfo()
//返回ServletConfig对象
ServletConfig getServletConfig()
ServletConfig接口的实现类对象,表示一个servlet在web.xml文件中的配置信息
//返回servlet在web.xml文件中所配置的名字
//也就是这个标签中的值
String getServletName()
//获得在web.xml中所配置的指定名字的参数值
//在web.xml可以通过标签给servlet传参
String getInitParameter(String name)
//获得给当前servlet传的所有参数的名字
Enumeration getInitParameterNames()
//获得ServletContext类型对象
//ServletContext是web项目中非常重要的一个类型对象
ServletContext getServletContext()
使用web.xml文件里面的这个
标签映射的路径,来访问servlet
这时候是get方式的访问,servlet中的doGet方法最终会被调用
这时候是get方式的访问,servlet中的doGet方法最终会被调用
这时候默认情况下是get方式访问,但是可以通过表单里的属性值进行设置为get或者post方式
这个时候也可以进行设置使用get方式还是post方式进行访问servlet
还可以使用标签语言来访问servlet
get方式访问
浏览器地址栏直接输入地址访问
超链接访问
外部js文件的引入
外部css文件的引入
表单提交数据method=“get”
在javascript代码中访问
在ajax中访问
使用jsp相关标签访问
post方式访问
表单提交数据method=“post”
ajax中设置本次请求为post方式
在http协议规范中,定义了四种访问方式(常见的)
get(查) post(改) put(增) delete(删)
http协议规范下的请求格式(分为四部分)
1部分: 请求行
2部分: 请求头部/消息报头
3部分: \r\n
4部分: 请求正文
get方式传参数 参数在uri后面(uri和url的区别)
GET /hello.html?name=tom HTTP1.1
key: value
key: value
key: value
…
\r\n
post方式传参 参数在请求正文中
POST /hello.html HTTP1.1
key: value
key: value
key: value
…
\r\n
name=tom
get和post的【传参】的安全性
get方式的参数由于是在地址栏中显示的,所以安全性低一些,post传参的时候参数在请求正文中,相对会安全一些。但是真正重要的数据在传的过程中还会更换协议http–>https,比如在网上支付的过程中
get和post在传参过程中参数长度的限制
get方式传参,参数长度是要看浏览器对地址栏中字符长度的限制,也就是要看浏览器对url地址的长度限制,我们只是把参数放到url后面了。url?参数=值
post方式参数,参数长度是要看服务器一次性最多能够接受并且处理多少数据
不管客户端是post方式还是get方式传参,只是参数存放的位置在传输过程有所变化,但是对于servlet接收参数来讲,俩种情况都是一样的接收
下面的测试是在这样的传参中进行的
http://127.0.0.1:8989/web_servlet/ParamServlet?name=tom&age=20&like=0&like=1
String name = request.getParameter("name");
String age = request.getParameter("age");
System.out.println(name);
System.out.println(age);
String[] like = request.getParameterValues("like");
System.out.println(Arrays.toString(like));
Enumeration<String> names = request.getParameterNames();
while(names.hasMoreElements()){
String str = names.nextElement();
System.out.println(str);
}
打印结果:
name
age
like
Map<String, String[]> map = request.getParameterMap();
for(String key:map.keySet()){
System.out.println(key+" : "+Arrays.toString(map.get(key)));
}
打印结果:
name : [tom]
age : [20]
like : [0, 1]
需要在tomcat服务器中server.xml文件中进行配置
在中加入新的属性URIEncoding="XXX"
在使用request获取参数【之前】,先把request中的编码进行设置
request.setCharacterEncoding("UTF-8");
String name = request.getParameter("name");
System.out.println(name);
http协议规范中响应的格式为:
1部分 响应状态行
2部分 响应头部/消息报头
3部分 \r\n
4部分 响应正文
如果响应头部信息中没有设置编码,那么浏览器会默认使用简体中文(GBK)来解析响应中的内容
所以在使用io流之前,需要设置一下response中的编码,同时还要告诉浏览器本次响应内容的编码是什么
//设置response中的编码为UTF-8
response.setCharacterEncoding(“UTF-8”);
//设置响应头部,告诉浏览器响应内容编码为utf-8
response.setContentType(“text/html;charset=utf-8”);
Unicode符号范围 | UTF-8编码方式
十六进制 二进制
0000 0000-0000 007F | 0xxxxxxx
0000 0080-0000 07FF | 110xxxxx 10xxxxxx
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx