文章目录
1 概述
服务器端编程
建动态服务端内容的过程:
1.CGI技术
2.微软的ASP和ASP.NET技术
3.基于Java的Servlet/JSP技术
Web容器
负责管理和运行Servlet
容器对Servlet的支持包括:
通信支持;生命周期管理;多线程支持;JSP支持;处理安全性。
HTTP请求
浏览器通过发送HTTP请求向服务器请求对资源的访问HTTP请求可以使用多种请求方法:
方法 | 作用 |
get | 请求获取所指定的资源 |
post | 请求服务器接收在请求中封装的实体 |
head | 请求获取所指定资源的响应信息报头 |
put | 请求服务器存储指定的资源 |
delete | 请求服务器刪除指定的资源 |
trace | 请求服务器回送收到的请求信息,主要用于测试 |
options | 请求服务器的性能或者查询与资源相关的选项 |
URL进入互联网的钥匙:
URL(统一资源定位符)的格式:http://host[":" post] [abs_path]
http表示使用http协议来定位网络资源
host表示合法的Internet主机域名或者IP地址
abs_path指定请求资源的URI(统一资源标识符)
URL应用举例:
http://www.renren.com/home.do
http://localhost:8080/ch05/index.jsp
2 Tomcat
2.1 Tomcat 容器模型
2.2 目录结构
静态网页发布
Request 请求
Response响应、回应
Config配置
Context上下文,环境
Attribute属性
Encoding字符编码
Parameter参数
3 Servlet
小服务程序或服务连接器(Java Servlet)
Servlet 为创建基于 web 的应用程序提供了基于组件、独立于平台的方法,可以不受 CGI 程序的性能限制。Servlet 有权限访问所有的 Java API,包括访问企业级数据库的 JDBC API。
Java Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。
使用 Servlet,您可以收集来自网页表单的用户输入,呈现来自数据库或者其他源的记录,还可以动态创建网页。
优点:
1.性能明显更好。
2.Servlet 在 Web 服务器的地址空间内执行。这样它就没有必要再创建一个单独的进程来处理每个客户端请求。
3.Servlet 是独立于平台的,因为它们是用 Java 编写的。
4.服务器上的 Java 安全管理器执行了一系列限制,以保护服务器计算机上的资源。因此,Servlet 是可信的。
4.Java 类库的全部功能对 Servlet 来说都是可用的。它可以通过 sockets 和 RMI 机制与 applets、数据库或其他软件进行交互。
Servlet工作原理解析,参考文档
https://www.ibm.com/developerworks/cn/java/j-lo-servlet/index.html
3.1 Servlet创建
Servlet接口中的方法:
1.void init(ServletConfig config)第一次请求servlet时初始化;(servlet对象创建的时候执行)
ServletConfig:代表的是该servlet对象的配置信息
2.void service(ServletRequest request,ServletResponse response)处理用户请求且做出响应;(每次请求都会执行)
ServletRequest:代表请求,认为ServeletRequest内部封装的是http请求
ServeletResponse:代表响应 认为要封装的是响应的信息
3.void destory()从容器中销毁该Servlet实例;(servlet销毁的时候执行)
Servlet 的生命周期:
1.实例化/创建(使用构造方法创建对象)
2.初始化 执行init方法
3.服务 执行service方法
4.销毁 执行destroy方法
何时创建:默认在第一次访问servelet 的时候创建对象
何时销毁:服务器关闭servlet就销毁了
每次访问必然执行的方法:service
生命周期完整图:
web资源访问:
3.1.1 实现 Servlet 接口
public class ServletDemo1 implements Servlet {
//public ServletDemo1(){}
//生命周期方法:当Servlet第一次被创建对象时执行该方法,该方法在整个生命周期中只执行一次
public void init(ServletConfig arg0) throws ServletException {
System.out.println("======init======");
}
//生命周期方法:对客户端响应的方法,该方法会被执行多次,每次请求该servlet都会执行该方法
public void service(ServletRequest arg0, ServletResponse arg1)
throws ServletException, IOException {
System.out.println("======hehe(service)========");
}
//生命周期方法:当Servlet被销毁时执行该方法
public void destroy() {
System.out.println("******destroy**********");
}
//当停止tomcat时也就销毁的servlet。
public ServletConfig getServletConfig() {
return null;
}
public String getServletInfo() {
return null;
}
}
abstract class GenericServlet implements Servlet,ServletConfig{
//GenericServlet通过将ServletConfig赋给类级变量
private trServletConfig servletConfig;
public void init(ServletConfig servletConfig) throws ServletException {
this.servletConfig=servletConfig;
/*自定义init()的原因是:如果子类要初始化必须覆盖父类的init() 而使它无效 这样
this.servletConfig=servletConfig不起作用 这样就会导致空指针异常 这样如果子类要初始化,
可以直接覆盖不带参数的init()方法 */
this.init();
}
//自定义的init()方法,可以由子类覆盖
//init()不是生命周期方法
public void init(){}
//实现service()空方法,并且声明为抽象方法,强制子类必须实现service()方法
public abstract void service(ServletRequest request,ServletResponse response)
throws ServletException,java.io.IOException{
}
//实现空的destroy方法
public void destroy(){ }
}
3.1.2 继承抽象类GenericServlet
实现了 Servlet 接口除了 service 的方法,不过这种方法极少用
public class ServletDemo2 extends GenericServlet {
@Override
public void service(ServletRequest arg0, ServletResponse arg1)
throws ServletException, IOException {
System.out.println("hahaha");
}
}
3.1.3 继承抽象类HttpServlet
常用方法
@WebServlet(name="servletDemo",urlPatterns = {"/a/login"}) // /a虚拟目录,以当前项目为路径
public class ServletDemo extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
System.out.println("========haha===========");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
System.out.println("========hehe=======");
doGet(req,resp);
}
}
3.2 Servlet 部署
<web-app>
//实例化
<servlet>
<servlet-name>HelloWorld</servlet-name>
<servlet-class>com.HelloWorld</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloWorld</servlet-name>
<url-pattern>/HelloWorld</url-pattern>
</servlet-mapping>
</web-app>
需要注意的是url-pattern这里写的是/HelloWorld,而在jsp中form表单的action写的是HelloWorld,而不是/HelloWorld。
4 详解
4.1 数据容器
数据容器:
ServletContext 上下文:整个应用环境使用同一个;
setAttribute(name,value) 、 getAttribute(name)
HttpSession 会话:同一个会话环境同一个;(使用率最高,前后端分离无session)
HttpServletRequest 请求:同一个请求对象。(仅当前的应用)
4.1.1 HttpServletRequest
HttpServletResponse 处理请求后,作为返回的响应数据
Servlet中获得提交表单中信息的方法:
-
String value = request.getParameter(name);
功能:
a) 获得提交表单中的指定字段信息
name --> 和表单中的字段名字对应
b) 获得URL中?后面的指定参数值
name --> 和?后面的参数名对应 -
String[] array = request.getParameterValues(name);
功能:获得同一个字段名字下的多个值,封装到一个数组中,通常用于checkbox中。 -
Enumeration e = request.getParameterNames();
功能:获得提交表单中所有字段的名字,封装到一个枚举类型中。 -
String queryString = request.getQueryString();
功能: 获得URL中?后面的字符串
4.1.2 会话跟踪技术
当前浏览器与服务器间多次的请求、响应关系,被称作一个会话。
session
流程:
客户端第一次请求服务器,服务器会为这个请求创建HttpSession对象,并且创建sessionID,然后放入session容器中;然后把sessionID放入响应对象中(HTTPServletResponse),响应给客户端,客户端接收响应信息,获取sessionID,把sessionID放入cookie中客户端发出第二次请求,请求对象会携带sessionID,然后服各获取请求对象中的sessionID,与服务器session容器中的SessionID一对一对比, 对比存在获得对应HttpSession对象,对比失败,创建HttpSession对象,并且创建新的sessionID,然后放入session容器中, 然后把sessionID放入响应对象中(HTTPServletResponse),响应给客户端。
session的生命周期
第一次请求就获得会话
主动调用销毁方法的时候,或者生命时间失效(默认30分钟),刷新Tomcat,浏览器关闭
session.getMaxInactiveInterval();最大生命时间,默认1800s。
会话的创建
使用HttpServletRequest接口的getSession()方法创建会话对象。
在servlet获得session: request.getSession();
方法:
void setAttribute(String name,Object object)
Object getAttribute(String name)
void removeAttribute(String name)
String getId() 获取当前session的Id
void invalidate() 销毁session对象
boolean isNew() 判断session是否新创建的
cookie
用于存储会话数据
Cookie cookie = new Cookie("name","xixi");
//后端给cookie添加数据,然后利用响应对象返回
response.addCookie(cookie);
response.sendRedirect("index.jsp");
技术核心:
1)构造Cookie对象
Cookie(java.lang.String name, java.lang.string value)
2)设置cookie
void setPath(java.lang.String uri) : 设置cookie的有效访问路径
void setMaxAge(int expiry) :设置cookie的有效时间
void setValue(java.lang . String newValue) :设置cookie的值
3)发送cookie到浏览器端保存
void response. addCookie(Cookie cookie) : 发送cookie
4)服务器接收cookie
Cookie[] request.getCookies() :接收cookie
Cookie技术:会话数据保存在浏览器客户端。
Session技术:会话数据保存在服务器端。
4.2 跳转方式
4.2.1 转发过程
request.getRequestDispatcher.forWard(request,response);
客户首先发送一个请求到服务器端,服务器端发现匹配的servlet,并指定它去执行,当这个servlet执行完之后,它要调用getRequestDispacther()方法,把请求转发给指定的student_list.jsp,整个流程都是在服务器端完成的,而且是在同一个请求里面完成的,因此servlet和jsp共享的是同一个request,在servlet里面放的所有东西,在student_list中都能取出来,因此,student_list能把结果getAttribute()出来,getAttribute()出来后执行完把结果返回给客户端。整个过程是一个请求,一个响应。
4.2.2 重定向过程
response.sendRedirect("/index.jsp");
客户发送一个请求到服务器,服务器匹配servlet,这都和请求转发一样,servlet处理完之后调用了sendRedirect()这个方法,这个方法是response的方法,所以,当这个servlet处理完之后,看到response.senRedirect()方法,立即向客户端返回这个响应,响应行告诉客户端你必须要再发送一个请求,去访问student_list.jsp,紧接着客户端受到这个请求后,立刻发出一个新的请求,去请求student_list.jsp,这里两个请求互不干扰,相互独立,在前面request里面setAttribute()的任何东西,在后面的request里面都获得不了。可见,在sendRedirect()里面是两个请求,两个响应。
Forward是在服务器端的跳转,就是客户端一个请求发给服务器,服务器直接将请求相关的参数的信息原封不动的传递到该服务器的其他jsp或servlet去处理,而sendredirect是在客户端的跳转,服务器会返回给客户端一个响应报头和新的URL地址,原来的参数什么的信息如果服务器端没有特别处理就不存在了,浏览器会访问新的URL所指向的servlet或jsp,这可能不是原先服务器上的webservce了。
4.2.3 重定向,转发区别
- 转发携带参数;
- 转发地址栏没有变化,重定向地址改变;
- 转发在服务器端完成的;重定向是在客户端完成的;
- 转发的速度快;重定向速度慢;(重定向效率高)
- 重定向:以前的request中存放的变重全部失效,并进入一个新的request作用域。
转发:以前的request中存放的变里不会失效,就像把两个页面拼到了一起。增加服务器压力。 - 转发不会执行转发后的代码;重定向会执行重定向之后的代码;
- 转发的是同一次请求;重定向是两次不同请求;
- 转发必须是在同一台服务器下完成;重定向可以在不同的服务器下完成
遇到的问题
1 报错信息
-
200:运行成功
-
400:客户端发送的请求不能找到你的具体的页面或者地址;绑定参数的时候出现异常。
-
404:服务器依据请求资源路径找不到对应的资源:配置xml有问题;一般都是请求地址对应不正确或者地址中由于自己拼接部分连接符中的缺失导致。
< 1 >错误原因:
a. 请求地址写错了
b.< servlet-name >不一致
< 2 >解决方式:
a. 依据http://ip:port/appname/servlet-url检查请求地址。
b. 检查web.xml文件。 -
405:方法异常
< 1 >错误原因:
service方法不正确,例如get,post方法
< 2 >解决方式:
检查service方法(方法名、返回类型、参数类型、异常类型)。 -
500:运行时出错,后端代码问题,服务器内部错误
< 1 >错误原因:
a. 配置文件类名写错了。
b. 没有继承HttpServlet。
c. 程序代码写错。
< 2 >解决方式:
a. 检查web.xml文件。servlet-class中有没有把类名写错(必须是完整类名)
b. 检查程序代码。 -
503:检查环境变量path和JAVA_HOME的环境变量,让JDK与Tomcat的版本保持一致。
-
302:重定向
2 idea端口被占用
第一种是找到占用此端口的应用将它关闭:
先查找占用1099端口的应用,打开cmd命令窗口,输入netstat -ano|grep 1099(netstat -aon|findstr 1099 查询被占用的端口)命令,从结果中可以看到1099端口被进程为1400的应用占用;
在任务栏右击,出现弹框,选择任务管理器,打开任务管理器窗口,选择详细信息tab标签,点击PID项进行排序,找到1400进程号;
之前启动的java项目没有正常关闭导致的,如果是不再使用的应用,我们则可以关闭它。右击选择结束任务即可关闭此应用;
再次在cmd窗口输入netstat -ano|grep 1099命令进行查看,此时1099端口不再使用,则可以正常启动我们的项目了。
第二种是修改此项目的启动配置端口
3 解决中文乱码问题
1、post方式解决方案:
request.setCharacterEncoding(“utf-8”);
response.setCharacterEncoding( “utf-8” );
response.setContentType(“text/html;charset=UTF-8”);
2、get方式
String string = request.getParamers("");
String str = new String(string.getBytes(“ISO8859-1”,“utf-8”));
3、修改tomcat的server.xml
< Connector port=“8080” protocol=“HTTP/1.1” connectionTimeout=“20000”
redirectPort=“8443” URIEncoding=“utf-8” />
< Connector port=“8080” protocol=“HTTP/1.1” connectionTimeout=“20000”
redirectPort=“8443” useBodyEncodingForURI=“true” />
4、修改tomcat的logging.properties,控制台打印中文信息
java.util.logging.ConsoleHandler.encoding = GBK
5、修改idea中Tomcat配置:
VM option: -Dfile.encoding=UTF-8
6、超链接也是get方式,form表单一般是post方式提交