一: Servlet要点
01.Servlet规范和搭建JavaWeb项目
什么是Service:
Service是JavaEE的组件,service是一个程序类,要求必须实现javax.service.Service接口.
也是JavaEE中的规范.服务器其实是Service的实现,
搭建标准的JavaWeb的项目结构:
1.创建一个java项目:HelloServletWeb:
2.在HelloServletWeb中创建一个文件夹webapp,表示web项目的根;
3.在webAPP中创建WEB-INF文件夹,
4.在WEB-INF中创建文件夹:lib,classes
5.在WEB-INF中去Tomcat根/conf拷贝web.xml文件,只需要保留根元素.
6.把当前项目的classpath路径改成webapp/WEB-INF下的classes中.
02.第一个Servlet的程序
Service的第一个程序编写步骤:
1):拷贝Tomcat根/lib/servlet-api.jar到项目的WEB-INF/lib目录中,并做build path.
2):编写Servlet程序,使之实现javax.servlet.Servlet接口,并覆盖接口中的方法.
public class HelloServlet implement javax.servlet.Servilet(...实现方法...)
3):发现方法中的参数出现arg0,arg1的情况是因为没有关联Servlet的源代码.
是否关联源代码和程序最终的运行没有关系,只是在开发阶段参数美观,可阅读源代码.
4):在service(ServletRequest req, ServletResponse res)方法,打印一句话.
引导:此时HelloServlet类,和Tomcat一点关系都没有:我们需要告诉Tomcat来帮我们管理HelloServlet类,
(Tomcat是Servlet的容器,会负责Servlet对象的声明)所以,得以配置的形式,告诉Tomcat来帮我们管理自定义的Servlet类.
5):Servlet配置:在web.xml文件中的配置,切记<url-pattern>/hello</url-pattern>中的hello要加"/"
6):部署项目并访问:server.xml中:<Context docBase="D:\Java EE\Servlet\webapp" path="day3">
访问:http://ip:port/contextPath/资源名
http://localhost:80/day3/hello
03.Servlet的生命周期方法
Servlet的生命周期:创建对象,初始化操作,运行操作,销毁操作.
javax.servlet.Servlet接口中的方法:
String getServletInfo():获取Servlet的信息(Servlet的作者,版本,版权相关).
ServletConfig getServletConfig();获取Servlet的配置信息对象.
生命周期方法:在WEB的生命周期中(Tomcat启动-->Tomcat关闭),Servlet是单例的.
构造器:在服务端程序第一次被请求的时候,调用,只被调用一次.
void init(ServletConfig config);在构造器执行完毕之后,调用init方法,也只会执行一次.
void service(ServletRequest req, ServletResponse resp):每一次请求都会执行该方法.
void destroy();正常关闭Tomcat才会执行(该方法不一定会被执行,我们没有必要在其中编写扫尾的操作).
总结: 构造器--->init方法---> {servlet方法}循环 ---->destory方法
注意:
1):Servlet类的构造器必须使用public修饰.
2):Servlet类必须是无参数构造器.
原因:底层创建Servlet对象:class.newInstance()方式.--->公共的无参数构造器.
总结:保证Servlet必须有一个公共的无参数构造器,方便Tomcat底层创建Servlet的对象.
04.Servlet的请求流程-图片版
05.Servlet的请求流程-文字版
1:浏览器先发送请求:http://localhost:80/day3/hello
2:DNS解析域名(忽略)
3:Tomcat解析请求:/day3/hello. 上下文路径:/day3 资源的名称/hello
4:解析Tomcat根/conf/server.xml文件,获取其中所有的<Context/>元素,并找到path属性为/day3的元素.
<Content docBase="D:\Java EE\Servlet\webapp" path="day3"/>.
再读取该<Content/>元素,再获取docBase属性值,该属性值就是当前访问的WEB项目的根路径.
5:从该web的根路径/WEB-INF下找到web.xml文件.
6:读取web.xml文件,获取所有的<url-patten>元素,并判断哪一个<url-pattern>的文本内容为:/hello.
找不到:报404错误. 找到:GOTO 7.
7:通过/hello ,找到当前Servlet的全限定名:com._520it._01_hello.HelloServlet
8:从Servlet的实例缓存池中去获取com._520it._01_hello.HelloServlet对应的对象
Map<String,Servlet> cache = ....;
Servlet obj = cache.get("com._520it._01_hello.HelloServlet");
if(obj==null){
//第一次请求:GOTO 9
}else{
//非第一次请求:GOTO 12
}
9:使用反射创建Servlet对象.
Servlet obj = Class.forName("com._520it._01_hello.HelloServlet").newInstance();
10:把创建的Servlet对象,存储到Servlet实例缓存池中,供下一次请求使用.
cache.put("com._520it._01_hello.HelloServlet",obj);
11:容器创建ServletConfig对象,并调用init方法,来完成初始化操作.
obj.init(config);
12:容器创建ServletRequest和ServletResponse对象,并调用service方法.
obj.service(req,resp);
13:在service方法中对,当前请求的客户端做响应
06.ServletConfig接口获取初始化参数
ServletConfig接口:表示Servlet的信息配置对象(web.xml中,当前Servlet的配置信息).
其中方法:
String getServletName();获取当前Servlet的名字,<servlet-name>元素的文本内容.
ServletContext getServletContext();获取当前Servlet的指定的参数名获取初始化参数值.
Enumeration<String> getInitParameterName();获取当前Servlet的所有初始化参数的名字.
07.Servlet继承体深入讲解系列
public class Servlet1 extends MyHttpServlet{
private static final long serialVersionUID = 1L;
public void service(HttpServletRequest req, HttpServletResponse resp) {
super.service(req, resp);
System.out.println("utf");
}
}
public class MyHttpServlet extends MyGenericServlet{
private static final long serialVersionUID = 1L;
//只能处理一般的请求
public void service(ServletRequest req, ServletResponse resp){
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
service(request,response);//获取请求方式,GET/POST
}
//专门处理Http的请求
public void service(HttpServletRequest req, HttpServletResponse resp){
String method = req.getMethod();//获取请求方式,GET/POST
if("GET".equals(method)){
doGet(req,resp);
}else{
doPost(req,resp);
}
}
//专门用于处理POST请求
private void doPost(HttpServletRequest req, HttpServletResponse resp) {
System.out.println("Servlet1.doPost()");
}
//专门用于处理GET请求
private void doGet(HttpServletRequest req, HttpServletResponse resp) {
System.out.println("Servlet1.doGet()");
}
}
abstract public class MyGenericServlet implements Serializable,Servlet,ServletConfig{
private static final long serialVersionUID = 1L;
private ServletConfig config = null;
public void init(ServletConfig config) throws ServletException {
this.config = config;
this.init();
}
//专门暴露给子类,让子类编写自身的初始化代码
public void init(){
//NO OP
}
@Override
abstract public void service(ServletRequest req, ServletResponse resp) throws ServletException, IOException;
//把ServletConfig对象暴露给子类访问
public ServletConfig getServletConfig() {
return this.config;
}
public String getServletInfo() {
return null;
}
public void destroy() {
}
public String getServletName() {
return config.getServletName();
}
public ServletContext getServletContext() {
return config.getServletContext();
}
public String getInitParameter(String name) {
return config.getInitParameter(name);
}
public Enumeration<String> getInitParameterNames() {
return config.getInitParameterNames();
}
}
8.Servlet继承体系总结和开发Servlet
前端web实际开发的时候只需继承HttpServlet类,调用service()方法,并记得删除方法中的super.service(req,resp);
9.HttpServletRequest接口和常用方法
String getInitParameter(String name):获取初始化参数,初始化参数是开发人员设置的
String getParameter(String name):获取用户输入的参数,参数是不同的用户输入的(通过表单)
常用方法:
01.String getMethod():返回请求方式:如GET/POST 只有表单中method=post才是post
02.String getRequestURI();返回请求行中的资源名字部分:如/test/index.html
03.StringBuffer getRequestURL():返回浏览器地址栏中所有的信息
04.String getContextPath():返回当前项目的上下文路径(<Context/>元素的path属性值.)
05.String getRemoteAddr():返回发出请求的客户机的IP地址
06.String getHeader(String name):返回指定名称的请求头的值
获取请求参数的方法:
01.String getParameter(String name):返回指定参数名字的值
02.String[] getParameterValues(String name):返回指定名字参数的多个参数值.
03.Enumeration<String> getParameterNames()返回所有的参数名的Enumeration对象
04.Map<String,String[]> getParameterMap():返回所有的参数和值所组成的Map对象.
10.处理请求中文乱码问题
在Tomcat中,对于POST和GET请求,都默认才有ISO-8859-1的编码方式.
而ISO-8850-1不支持中文,所以乱码.
解决方案:
1:按照ISO-8859-1把乱码恢复成二进制形式
byte[] data = username.getBytes("ISO-8859-1");
2:再把二进制形式的数据使用UTF-8重新编写
String username = new String(data,"UTF-8");
一个参数需要使用两行代码来转码,如果有N个参数,需要转N次代码重复.
解决方案:
针对于POST的请求方式: req.setCharacterEncoding("UTF-8");
注意:1.只对POST有效. 2:必须放在获取任意参数之前.
针对于GET的请求方式:修改Tomcat中的server.xml配置文件,对GET方式的默认编码.
URIEncoding="ISO-8859-1"改为"UTF-8"
11.HttpServletResponse接口和常用方法
ServletResponse接口:响应对象.封装了获取响应信息的方法.
HttpServletResponse接口:ServletResponse的子接口,可以处理HTTP响应的方法.
常用方法:
01.OutputStream getOutputStream();获取字节输出流对象. 输出图片等
注意:可以一起输出多个getOutputStream(),但是不可以跟getWriter()一起使用:
02.PrintWriter getWriter():获取字符流输出对象 输出英文或者中文等
03.设置输出数据的MIME类型:resp.setContentType("text/html");
04.设置输出数据的编码方式:resp.setCharacterEncoding("UTF-8");
可以将上述3,4两行代码合并成一行代码:resp.setContentType("text/html;charset=UTF-8");
注意:必须先设置MIME类型和编码,再获取输出流,否则没有效果.
12.网页版的简易计算器
静态网页版
<!DOCTYPE html>
<html>
<head>
<meta charset='UTF-8'>
<title>Insert title here</title>
</head>
<body>
<form action='/cal' method='post'>
<input type='number' name='num1' />
<select name='op'>
<option>+</option>
<option>-</option>
<option>*</option>
<option>/</option>
</select>
<input type='number' name='num2' />
<input type='submit' value=' = '/>
<input type='text' value='' disabled />
</form>
</body>
</html>
动态的Servlet网页
public class CalServlet extends HttpServlet{
private static final long serialVersionUID = 1L;
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=UTF-8");
PrintWriter out = resp.getWriter();
//================================
//2:接受表单中的数据
String snum1 = req.getParameter("num1");
String op = req.getParameter("op");
String snum2 = req.getParameter("num2");
String result = "";
if(haslength(snum1) && haslength(snum2)){
Integer num1 = Integer.valueOf(snum1);
Integer num2 = Integer.valueOf(snum2);
if("+".equals(op)){
result = num1+num2+"";
}else if("-".equals(op)){
result = num1*num2+"";
}
}
//================================
//1:输出一个计算器的界面
out.print("<form action='/cal' method='post'>");
out.print("<input type='number' name='num1' value='"+snum1+"'/>");
out.print("<select name='op'>");
out.print("<option>+</option>");
out.print("<option>-</option>");
out.print("<option>*</option>");
out.print("<option>/</option>");
out.print("</select>");
out.print("<input type='number' name='num2' value='"+snum2+"'/>");
out.print("<input type='submit' value=' = ' />");
out.print("<input type='text' value='"+result+"' disabled/>");
}
private boolean haslength(String str){
return str!=null && !"".equals(str.trim());
}
}