javaWeb学习之Servlet
1.javaWeb初识
Web概述:web(World Wide Web)即全球广域网,也称为万维网,它是一种基于超文本和HTTP的、全球性的、动态交互的、跨平台的分布式图形信息系统。是建立在Internet上的一种网络服务,为浏览者在Internet上查找和浏览信息提供了图形化的、易于访问的直观界面,其中的文档及超级链接将Internet上的信息节点组织成一个互为关联的网状结构。
JavaWEB概述:使用java语言进行WEB开发
软件架构
1.CS结构的软件
- CS:Client/Server客户端和服务端,这种软件往往需要安装,比如QQ,迅雷等
- 优缺点:
- 优点
- 可以减轻服务器端压力,将部分代码写到客户端
- 界面很美观
- 优点
- 缺点:
- 一旦服务器更新,客户端也需要更新
- 分布式开发比较弱
2.BS结构的软件
- BS:Brower/Server浏览器和服务器,这种软件不需要安装,只需要通过浏览器就可以访问
- 优缺点:
- 优点:
- 服务器一旦更新,不需要更新客户端,因为客户端就是浏览器
- 比较强的分布式能力
- 缺点(现在的缺点也已经得到解决了,所以BS架构将是大势所趋啊):
- 服务器端压力比较大
- 界面效果不如CS结构软件
- 优点:
WEB服务器
服务器包括:
- 硬件:其实就是一台电脑(这台电脑配置要求很高)
- 软件:需要在这台电脑上安装web服务器的软件
常见的WEB服务器(软件)
- Tomcat:Apache组织提供的一个开源的免费的web服务器,满足了javaEE的Serlet和JSP的规范
- WebSphere:IBM公司开发的一个收费的大型web服务器,满足了javaEE开发的所有规范
- WebLogic:BEA公司开发的一个收费的大型web服务器,满足了javaEE开发的所有规范
- IIS:应用在.NET平台上
- Apache:应用在PHP平台上
WEB开发中的资源
1.静态web资源
- HTML
- CSS
- JS
2.动态web资源
- Servlet、JSP
- PHP
- ASP
2.Tomcat
tomcat概述:Apache组织提供的一个开源的免费的web服务器,满足了javaEE的Serlet和JSP的规范
Tomcat的安装
1.下载Tomcat
2.解压
解压后的目录如下:
3.启动tomcat
进入tomcat的bin目录下,找到startup.bat,然后双击startup.bat即可启动tomcat(注意这里双击startup.bat会开启一个dos窗口,不要关闭它,关闭则会关闭tomcat服务器)
4.测试tomcat是否启动成功
在浏览器的地址栏上输入:http://localhost:8080/
如果有以上画面,则代表启动成功。
Tomcat安装的注意事项
1.Tomcat运行需要依赖java环境,也就是说你的电脑上必须安装了JDK才能启动Tomcat成功,因为在Tomcat启动的时候需要使用JRE的环境,必须配置JAVA_HOME环境变量,如果没有配置JAVA_HOME环境变量,那么服务器在启动的时候就会一闪然后关闭
2.Tomcat端口号冲突问题:如果电脑上的其他程序占用了Tomcat的默认端口8080或者你启动了两次Tomcat,则也会导致Tomcat启动不了(8080端口被占用的概率很小,但是80端口被占用的概率就很大,因为80端口是http的默认端口),如果遇到了端口冲突问题,怎么办呢?
解决方法:
- 将占用端口的程序结束掉
- 输入命令查看各个程序占用的端口号:netstat -ano
- 找到谁占用了之后,在任务管理器中结束这个程序即可(任务管理器的详细信息里操作结束)
- 改变自身端口号
- 进入到tomcat目录下的conf目录下的server.xml文件里进行修改
- 这个server.xml文件里的 <Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />就配置了我们的默认端口号信息
Tomcat的目录结构介绍
- bin:存放一些二进制文件(命令文件),如开启和关闭tomcat
- conf:存放一些配置文件
- lib:存放tomcat所需要的jar包
- logs:tomcat服务器日志文件
- temp:tomcat运行产生临时文件
- webapps:需要发布的项目需要放在webapps下
- work:jsp翻译成servlet产生的代码
动态web资源的目录结构
website
|------静态页面(HTML、CSS、JS、图片)
|------JSP页面
|------WEB-INF
|-----web.xml (必须的)
|-----classes (可选的)
|-----lib (可选的)
Tomcat项目发布的方式
1.方式一:直接将项目复制到tomcat/webapps下
2.方式二:在Tomcat/conf/server.xml配置tomcat的虚拟路径(官方不推荐)
- 在server.xml文件的Host标签里插入:<Context path="/虚拟的路径" docBase="/真实项目的路径"></Context>进行配置
3.方式三:在tomcat/conf/Catalina/localhost/下配置tomcat的虚拟路径(推荐使用)
- 在tomcat/conf/Catalina/localhost目录下创建一个xml文件,在这个xml文件中进行以下配置:<Context docBase="/真实项目的路径"></Context>,而我们的这个xml的名字就是我们访问真实项目的虚拟路径
3.HTTP协议
概述:规定了浏览器和服务器端的数据交互的格式
HTTP的特性
1.基于请求和响应模式
- 必须要先有请求,后有响应
- 请求和响应必须成对出现
2.简单快捷
- 因为发送请求的时候只需要发送请求方式和请求路径即可
HTTP之请求部分
1.请求行
- 请求方式:请求方式有很多种,常用的是get和post
- 请求路径
- 协议版本
2.请求头
- 请求头的一般格式都是一个key对应一个value的,也有一个key对应多个value的情况
- 记住一些请求头
- Referer:代表网页的来源(防盗链)
- User-Agent:获得客户端的浏览器类型
3.请求体
- 只有post请求方式才有请求体,而且请求体是post方式的请求参数
HTTP之响应部分
1.响应行
- 协议版本
- 状态码
- 200:代表响应成功
- 302:需要进行重定向操作
- 304:需要查找本地缓存
- 404:请求资源不存在
- 500:服务器内部错误
2.响应头
- 通常是一个key对应一个value的,也有一个key对应多个value的情况
- 记住一些响应头
- Location:重定向的路径
- Refresh:定时刷新
- Content-Disposition:文件下载的时候使用
3.响应体
- 就是显示到浏览器页面上的代码
4.Servlet
概述:Servlet其实就是一个运行在web服务器上的小的程序,用于处理从web客户端发送的请求,并且对请求做出响应
Servlet的使用
1.编写一个java类实现Servlet的接口
代码实现:
//web_text(web project项目)下的src目录下的HelloWorld.java
package cn.luyi.servlet;
import java.io.IOException;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class HelloWorld implements Servlet{
public void service(ServletRequest req, ServletResponse resp) throws ServletException, IOException {
resp.getWriter().println("HelloWorld");
}
public void destroy() {
// TODO Auto-generated method stub
}
public ServletConfig getServletConfig() {
// TODO Auto-generated method stub
return null;
}
public String getServletInfo() {
// TODO Auto-generated method stub
return null;
}
public void init(ServletConfig arg0) throws ServletException {
// TODO Auto-generated method stub
}
}
2.配置Servlet
配置web.xml:
//web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>web_text</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<!-- 配置Servlet -->
<servlet>
<!-- 配置Servlet的名称 -->
<servlet-name>HelloWorld</servlet-name>
<!-- 配置实现Servlet类的全路径 -->
<servlet-class>cn.luyi.servlet.HelloWorld</servlet-class>
</servlet>
<!-- 配置Servlet的映射 -->
<servlet-mapping>
<!-- 配置Servlet的名称 -->
<servlet-name>HelloWorld</servlet-name>
<!-- 配置访问路径 -->
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>
3.测试:通过http://localhost:8080/web_text/hello路径访问,页面上显示HelloWorld则成功啦
Servlet的实现关系
前面我们通过实现Servlet接口来实现往页面输出东西,但是我们只用到了一个方法service,却要重写所有的Servlet接口的方法,我们开发中是不会这么做的,所以,我们接下来就要学习通过继承Servlet的实现类来达到我们的目的
Servlet的两个实现类:GenericServlet类和HttpSrvlet类
- GenericServlet类:通用的Servlet,是一个与协议无关的Servlet
- HttpServlet类:Http专用的Servlet
通常我们编写一个Servlet都会让他继承HttpServlet并重写service方法,在service方法内部根据请求方式不同执行不同的doXxx的方法,如get请求方式则执行doGet方法,所以我们往往继承了HttpServlet之后不需要重写service方法,只需要重写doGet和doPost等方法即可
以上我们说的创建一个Servlet的方式,其实Eclise已经给我们提供了创建一个这样的Servlet的快捷方式(右键src目录下的包名,然后新建一个Servlet即可,它会自动配置web.xml文件)
Servlet的生命周期
Servlet生命周期:Servlet对象从创建到销毁的过程
Servlet中有init, service,destory方法,这几个方法称为是Servlet生命周期相关的方法
Servlet是在第一次被访问的时候会被实例化,只要servlet一被实例化,那么Servlet中的service方法就会执行,当servlet服务器移除或者服务器关闭的时候Servlet对象被销毁,里面的destory方法就会执行,然后垃圾回收就会将其回收
代码演示Servlet的生命周期:
import java.io.IOException;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class ServletDemo2 implements Servlet{
public void init(ServletConfig config) throws ServletException {
System.out.println("init方法");
}
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
System.out.println("service方法");
}
public void destroy() {
System.out.println("destory方法");
}
public ServletConfig getServletConfig() {
// TODO Auto-generated method stub
return null;
}
public String getServletInfo() {
// TODO Auto-generated method stub
return null;
}
}
//浏览器一访问,就会执行init方法和service方法,停掉服务器,就会执行destory方法
Servlet的启动时配置
Serclet对象是第一次被访问的时候被创建的,init方法就会执行,假设在init方法中做了一些比较耗时的操作(比如加载一些配置文件并解析花费了3秒钟),第一个用户第一次访问这个Servlet的时候,就需要等待3秒钟,那么,我们如何使得第一个用户在第一次访问的时候不需要花费这么长时间呢?
这就需要我们对Servlet进行启动时加载配置了,现在,我们通过一个配置将Servlet的实例化的过程放在服务器启动的时候(让服务器启动的时候创建Servlet的对象),如果现在这样做,那么之前花费的时间就会在服务器启动的时候一起花费掉了,对于用户来讲就不需要额外花费这个时间了,那么如何进行启动时配置呢?
我们的这个配置是在web.xml中进行配置的,哪个servlet就在哪个servlet标签中进行启动时配置,这个配置标签为load-on-startup,这个标签中放一个整数,整数越小,代表启动时加载的优先级越高,一般配置在2以上,因为我们的Tomcat有一个默认Servlet的优先级为1,我们不能比他高
web.xml进行Servlet启动时加载配置:
<!-- 配置Servlet -->
<servlet>
<!-- 配置Servlet的名称 -->
<servlet-name>HelloWorld</servlet-name>
<!-- 配置实现Servlet类的全路径 -->
<servlet-class>cn.luyi.servlet.HelloWorld</servlet-class>
<!-- 配置该Servlet启动时加载,优先级为2-->
<load-on-startup>2</load-on-startup>
</servlet>
<!-- 配置Servlet的映射 -->
<servlet-mapping>
<!-- 配置Servlet的名称 -->
<servlet-name>HelloWorld</servlet-name>
<!-- 配置访问路径 -->
<url-pattern>/hello</url-pattern>
</servlet-mapping>
Servlet的访问路径
web.xml中url-pattern标签的配置的三种方式:
- 完全路径匹配:以/开始,比如/ServletDemo1
- 目录匹配:以/开始,以/*结束,比如/aaa/*
- 扩展名匹配:不能以/开始,以*开始,比如*.jsp
以上的这三种方式的访问优先级为:完全路径匹配>目录匹配>扩展名匹配
ServletConfig对象
概述:ServletConfig对象用来获得Servlet的相关配置的对象
获得ServletConfig对象:
- getServletConfig()
获得Servlet的初始化参数方法:
- String getInitParamter(String name):获得指定初始化参数值
- Enumeration getInitParameteNames():获得所有初始化参数的名称
获得Servlet的名称
- getServletName()
代码示例:
//web.xml关于Servlet的配置:
<servlet>
<servlet-name>ServletDemo4</servlet-name>
<servlet-class>cn.luyi.servlet.ServletDemo4</servlet-class>
<init-param>
<param-name>username</param-name>
<param-value>luyi</param-value>
</init-param>
<init-param>
<param-name>password</param-name>
<param-value>123</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>ServletDemo4</servlet-name>
<url-pattern>/ServletDemo4</url-pattern>
</servlet-mapping>
//ServletDemo4.java
package cn.luyi.servlet;
import java.io.IOException;
import java.util.Enumeration;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ServletDemo4 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获得ServletConfig对象
ServletConfig config = this.getServletConfig();
//获得初始化参数
String username = config.getInitParameter("username");
String password = config.getInitParameter("password");
System.out.println(username + "---" + password);
//获得所有初始化参数的名称
Enumeration names = config.getInitParameterNames();
while(names.hasMoreElements()){
String name = (String) names.nextElement();
String value = config.getInitParameter(name);
System.out.println(name + "---" + value);
}
//获得Servlet的名称
String servletName = config.getServletName();
System.out.println(servletName);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
ServletContext对象
概述ServletContext:Servlet的上下文对象,ServletContext对象对Servlet之前和之后的内容都知道,这个对象一个web项目只有一个,在服务器启动的时候为每个web项目创建一个单独的ServletContext对象
ServletContext对象的两个作用:
1.用来获取web项目信息
- 获取ServletContext对象:getServletContext()
- 获取文件的MIME类型:getMimeType(文件名)
- 获取路径工程名:getRealPath()
- 获取全局初始化参数:
- String getInitParamter(String name):获得指定初始化参数值
- Enumeration getInitParameteNames():获得所有初始化参数的名称
代码示例:
//web.xml
<context-param>
<param-name>username</param-name>
<param-value>luyi</param-value>
</context-param>
<context-param>
<param-name>password</param-name>
<param-value>123</param-value>
</context-param>
<servlet>
<servlet-name>ServletDemo5</servlet-name>
<servlet-class>cn.luyi.servlet.ServletDemo5</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ServletDemo5</servlet-name>
<url-pattern>/ServletDemo5</url-pattern>
</servlet-mapping>
//ServletDemo5.java
package cn.luyi.servlet;
import java.io.IOException;
import java.util.Enumeration;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ServletDemo5 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获得文件的MIME类型
ServletContext servletContext = this.getServletContext();
String mimeType = servletContext.getMimeType("aa.txt");
System.out.println(mimeType);
//获得当前工程名的绝对路径
String path = servletContext.getRealPath("/");
System.out.println(path);
//获得全局初始化参数
String username = servletContext.getInitParameter("username");
String password = servletContext.getInitParameter("password");
System.out.println(username + "---" + password);
Enumeration names = servletContext.getInitParameterNames();
while(names.hasMoreElements()){
String name = (String) names.nextElement();
String value = servletContext.getInitParameter(name);
System.out.println(name + "---" + value);
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
2.读取Web项目下的文件
之前使用IO流就可以读取文件(java项目中),现在是web项目,web项目需要发布到Tomcat下才能获得访问的,获取web项目下的文件如果使用传统的IO就会出现问题(原因:路径中使用的是相对路径,相对的是JRE环境)
- InputStream getResourceAsStream("/文件名"):读取文件名并作为输入流
ServletContext作为域对象:ServletContext是在服务器启动的时候为每个web项目单独创建一个ServletContext对象,当web项目从服务器中移除,或者是关闭服务器的时候,ServletContext对象会被销毁,向ServletContext中保存的数据一直存在(当服务器关闭的时候,ServletContext对象被销毁,然后里面数据才会失效),作用范围为整个web应用
使用ServletContext作为域对象的方法:
- setAttribute(String name, Object object):存入数据
- getAttribute(String name):取出数据
- removetAttribute(String name):移除数据
5.Response对象
概述:开发的软件是B/S结构的软件,可以通过浏览器访问服务器的软件,从浏览器输入一个地址访问服务器,这个过程就是请求。服务器接收到请求,需要进行处理,处理之后需要将处理结果显示回浏览器,这个过程就是响应了
Response对象的API
1.关于响应行的方法:
- setStatus(int sc):设置状态码
2.关于响应头的方法:
- setDateHeader(String name, long date):设置响应头的时间部分
- setHeader(String name, String value):设置响应头的一个个键值对信息(值为String类型),如果我们要设置的这个键已经存在,则重写设置为给定的这个值
- setIntHeader(String name, int value):设置响应头的一个个键值对信息(值为int类型),如果我们要设置的这个键已经存在,则重写设置为给定的这个值
- addDateHeader(String name, long date):设置响应头的时间部分
- addHeader(String name, String value):设置响应头的一个个键值对信息(值为String类型),如果我们要设置的这个键已经存在,则追加这个值
- addIntHeader(String name, int value):设置响应头的一个个键值对信息(值为int类型),如果我们要设置的这个键已经存在,则追加这个值
3.关于响应体的方法:
- getOutputStream():获取字节流
- getWriter():获取字符流
4.Response的其他API
- sendRedirect(String location):重定向方法
- setContentType(String type):设置浏览器打开页面时采用的字符集
- addCookie(Cookie cookie):服务器向浏览器回写Cookie的方法
Response对象的API的使用代码示例:
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ResponseDemo extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/*//设置状态码为302
response.setStatus(302);
//实现页面跳转
response.sendRedirect("/web_text/hello");*/
//定时刷新
//设置字符集以使得兼容中文
response.setContentType("text/html;charset=UTF-8");
response.getWriter().println("5秒后跳转");
//设置五秒后跳转到/hello页面
response.setHeader("Refresh", "5;url=/web_text/hello");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
Response对象响应的中文乱码处理
1.使用字节流的话,可能出现乱码,只要保证字节数组和浏览器默认打开时采用的字符集一样就不会出现乱码了
2.使用字符流的话,一定会出现乱码,原因是字符流是有缓冲区的,response获得字符流,response设计默认的缓冲区编码是IOS-8859-1,这个字符集不支持中文,解决这种情况导致的乱码就需要设置response获得字符流缓冲区的编码和设置浏览器默认打开时采用的字符集一致即可
设置的代码:
//设置浏览器默认打开时采用的字符集
response.setHeader("Content-Type", "text/html;charset=UTF-8");
//设置response获得字符流的缓冲区的编码
response.setCharacterEncoding("UTF-8");
//以上两条代码可简写为:
response.setContentType("text/html;charset=UTF-8");
6.Request对象
概述:开发的软件都是B/S结构软件,从浏览器向服务器提交一些数据时,将这些内容进行封装,封装成了一个请求对象
Request对象的API:
1.获得客户机信息
- getMethod():获得请求方式
- getQueryString():获取请求路径后得提交参数的字符串
- String getRequestURI():获取请求路径的URI
- StringBuffer getRequestURL():获取请求路径的URL
- String getRemoteAddr():返回客户端的ip地址
2.获得请求头的方法:
- String getHeader(String name):获得一个key对应一个value的请求头
- Enumeration getHeaders(String name):获得一个key对应多个value的请求头
3.获得请求参数的方法
- String getParameter():获取提交的参数(一个name对应一个value)
- String[] getParameterValues():获取提交的值(一个name对应多个value)
- Map getParameterMap():获取提交的参数,将提交的名称和对应的值存入到一个Map集合中去
4.Request作为域对象的方法
- void setAttribute(String name,Object o):向request域中存数据
- Object getAttribute(String name):向request域中取数据
- void removeAttribute(String name):从request域中移除数据
补充:Request作为域对象的作用范围:Request对象其实就是从客户端浏览器向服务器发送的一次请求信息的封装,那么实质上向Request中所保存的数据有效期也是一次请求范围,一次请求范围就是从客户端向浏览器发送一次请求后,服务器针对这次请求对浏览器做出响应,当服务器作出响应后,请求对象就销毁了,保存在其中的数据就无效了
Request对象的API代码示例:
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class RequestDemo extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取请求方式
System.out.println("请求方式" + request.getMethod());
//获得客户机的IP地址
System.out.println("客户机ip地址" + request.getRemoteAddr());
//获取请求参数的字符串(所有的参数和值)
System.out.println("请求参数" + request.getQueryString());
//获得请求头信息
System.out.println("浏览器类型为:" + request.getHeader("User-Agent"));
//获得请求参数的值
System.out.println("name参数的值为:" + request.getParameter("name"));
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
request对象接收请求参数为中文乱码处理
1.post请求:post方式提交的数据是在请求体中,request对象接收到数据之后,放入request的缓冲区,缓冲区就有编码(默认ISO-8859-1)
解决方案:将request的缓冲区的编码修改为UTF-8即可
修改代码:request.setCharacterEncoding("UTF-8")
2.get请求:get方式提交的数据在请求行的url后面,在地址栏上其实就已经进行了一次URL的编码了
解决方案:将存入request缓冲区的值以ISO-8859-1的方式获取到,以UTF-8的方式进行解码
修改代码:
//将存入request缓冲区的值以ISO-8859-1的方式获取到
String encode = URLEncoder.encode(参数, "ISO-8859-1");
//以UTF-8的方式进行解码
String decode = URLDecoder.decode(encode, "UTF-8");
//以上代码可以简写为:
String value = new String(参数.getBytes("ISO-8859-1"), "UTF-8");
作者:卢一
出处:http://www.cnblogs.com/luyi001/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。