02.Servlet技术 - 第1章.Servlet
Servlet简介
Servlet应用于?
浏览器发出HTTP请求,服务器收到请求后响应返回给浏览器。
接受请求后到返回响应之间:
服务器将请求对象转交给Servlet容器
Servlet容器根据HTTP请求的具体路径将请求转交给具体的Servlet
Servlet在收到请求后进行相应的处理逻辑后,将处理返回给服务器
服务器将HTTP响应返回给浏览器
Servlet是什么?
Servlet = server + applet --- 运行于server的applet
Applet(在web环境下运行与客户端的Java组件):没有main method,不能独立运行于JVM,需要特殊的容器装载进行,由容器管理生成销毁
Servlet:一个Servlet就是一个Java类,并提供基于请求-响应模式的Web服务
Servlet容器:装载和管理Servlet;为一个服务端程序,用于转交请求给Servlet
Eclipse中的Servlet配置:
prerequisite:Tomcat,Eclipse,Eclipse maven插件
配置Tomcat用户:
tomcat/conf/tomcat-users.xml
将文件中所有内容删除,加入以下内容并保存;
<?xml version='1.0' encoding='utf-8'?>
<tomcat-users>
<role rolename="manager-gui"/>
<role rolename="manager-script"/>
<user username="admin" password="123456" roles="manager-gui,manager-script"/>
</tomcat-users>
保存后启动Tomcat,访问localhost:8080
点击右侧Manager APP按钮,登陆,表示Tomcat管理员配置成功
Maven中配置Tomcat服务器:
修改Maven的配置文件~/.m2/setting.xml (different from maven/conf/setting.xml)
增加tomcat服务器:在<servers></servers>直接增加子元素
** 为什么要在maven的$user_home/.m2/settings.xml文件中设置tomcat的server服务?
因为maven项目的pom.xml文件中只是定义了server的地址,但是server的用户名以及密码或者私钥不能使用于pom.xml,所以要在maven全局的settings.xml中定义这个server。
<server>
<id>tomcat</id>
<username>admin</username>
<password>123456</password>
</server>
Tomcat Maven插件配置:
在项目的pom.xml 文件中的<plugins></plugins>直接增加子元素,增加代码:
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<url>http://localhost:8080/manager/text</url>
<path>/web_project_template</path>
<uriEncoding>UTF-8</uriEncoding>
<finalName>web_project_template</finalName>
<server>tomcat</server>
</configuration>
</plugin>
Servlet hello world:
在web.controller包下New Class – Superclass:HttpServlet
Override methods: doGet(HttpServletRequest,HttpServletResponse); service(HttpServletRequest,HttpServletResponse);
在service()中,System.out.println(“service method”);
重新doGet():
System.out.println("doGet method");
PrintWriter pw = resp.getWriter();
pw.print("hello world");
pw.close();
src->main->webapp->WEB_INF->web.xml 配置对应的Servlet
<servlet>
<servlet-name>TestServlet</servlet-name>
<servlet-class>com.netease.server.example.web.controller.TestServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>TestServlet</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
运行:
eclipse中对应的项目,右键Run As -- Run Configuration – 双击左侧菜单maven build以创建新的maven build -- Name: maven deploy; Brower Workspace: 所要部署的项目;
Goals: tomcat7:deploy
启动Tomcat,点击run即可进行部署。
// Eclipse内置Tomcat-plugin:http://www.jianshu.com/p/8da9ca8c0667
// eclipse internal web browser:Window->Show View->Other->Internal Web Browser
路径:http://localhost:8080/$project-path/$page-path
project-path: pom.xml中配置的<plugin>tomcat7-maven-plugin的path:/web_project_template
page-path: web.xml中配置的<servlet-mapping>url-pattern: /hello
Servlet处理流程:
浏览器中输入地址:http://localhost:8080/web_project_template/hello
Servlet容器根据地址和配置文件web.xml找到对应的Servlet:TestServlet.java
同时将请求传递给对应Servlet的Servlet方法
Servlet方法是Servlet的核心,每当客户端请求一个Servlet对象时,会调用该对象的service方法,并传递给Servlet方法一个HttpServletRequest对象和一个HttpServletResponse对象作为参数。
使用HTTP的get方法访问的Servlet,则Servlet方法会将响应的请求传递给doGet()来处理,post同理
在doGet()方法中通过HttpServletResponse对象将”hello world”返回给客户端
Servlet接口与实现类
Servlet生命周期:初始化、请求处理、销毁
初始化:init():客户端第一次请求Servlet时,Servlet容器会创建Servlet对象的实例,此时Servlet容器会调用Servlet的init();如果在配置文件中配置了loadOnSetup元素,则Servlet会在容器启动时做响应的加载。
请求处理:service():将不同的HTTP请求转发给不同的Servlet方法,常用doGet() doPost()
销毁:destroy():由Servlet容器对Servlet进行资源回收和清理
进入Tomcat主页右边点击App Manager,会看到所有部署的引用,点击web_project_template的stop,会执行destroy()
想要在Servlet进行逻辑处理之前做一些准备工作,或在Servlet实例销毁之前进行资源回收或清理的工作:
i.e. override method: init(); destroy();
init(); or init(ServletConfig config);?一般情况下选择init();
init()中:System.out.println(“init method”);
destroy()中:System.out.println(“destroy method”);
3、Get以及Post的区别
传输方式上,Get的数据通过HTTP Header进行传输,Post是通过HTTP Body进行传输,另外Get的数据在URL中可见,Post的数据不可见。
因为是在URL中传输数据,所以Get的长度有限制,Post基本没有。
传输目的:Get是为了获取数据,Post是为了发送数据。
安全性,POST方法相对更安全,因为它不会显示数据,而且有编码。
i.e.
下面这个getPostTest.html文件里有2个form表单,分别是get方法以及post方法提交。
代码区域:
<body>
<form action="servlet/GetPostServlet" method="GET">
用户名: <input type=text name=name1 value=""> 密码: <input
type=password name=pw1 value=""><br> <input
type="submit" value="使用GET提交"> <br>
</form>
-----------------------------------------------------------------------------
<br></br>
<form action="servlet/GetPostServlet" method="POST">
用户名: <input type=text name=name2 value=""> 密码: <input
type=password name=pw2 value=""><br> <input
type="submit" value="使用POST提交">
</form>
</body>
对应有Servlet对象GetPostServlet.java
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
String name1 = request.getParameter("name1");
String pw1 = request.getParameter("pw1");
out.println("<HTML>");
out.println(" <HEAD><TITLE>A Servlet</TITLE></HEAD>");
out.println(" <BODY>");
out.print(" 调用doGet 方法 ");
out.println("<br></br>");
out.println("用户名:" + name1);
out.println("<br></br>");
out.println("密码:" + pw1);
out.println(" </BODY>");
out.println("</HTML>");
out.flush();
out.close();
}
@Override
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
String name2 = request.getParameter("name2");
String pw2 = request.getParameter("pw2");
out.println("<HTML>");
out.println(" <HEAD><TITLE>A Servlet</TITLE></HEAD>");
out.println(" <BODY>");
out.print(" 调用doPost 方法 ");
out.println("<br></br>");
out.println("用户名:" + name2);
out.println("<br></br>");
out.println("密码:" + pw2);
out.println(" </BODY>");
out.println("</HTML>");
out.flush();
out.close();
}
在web.xml对应servlet元素
<servlet>
<servlet-name>GetPostServlet</servlet-name>
<servlet-class>com.netease.server.example.web.controller.GetPostServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>GetPostServlet</servlet-name>
<url-pattern>/servlet/GetPostServlet</url-pattern>
</servlet-mapping>
部署后,地址栏http://localhost:8080/web_project_template/getPostGet.html
点击按钮会跳转到 web_project_template/servlet/GetPostServlet
不同的是get提交的url为 http://localhost:8080/web_project_template/servlet/GetPostServlet?name1=admin1&pw1=nopass.a1
而post提交的url为
http://localhost:8080/web_project_template/servlet/GetPostServlet
Servlet配置参数
实际的开发过程中经常要用到参数,用到配置信息(比如数据库,编码等)
String db_url = “jbdc:mysql://localhost/TEST”;
String user = “userjake”;
String password = “123456”;
类似于上面这种“硬编码”就是不好的习惯,代码的维护成本会高。
那么如何在Servlet中配置一些固定的参数?
这就需要用到ServletConfig这个对象。
首先,需要在配置文件web.xml中配置参数;
<servlet>
<init-param>
<param-name>data1</param-name>
<param-value>value1</param-value>
</init-param>
<init-param>
<param-name>data2</param-name>
<param-value>value2</param-value>
</init-param>
<servlet-name>ServletConfigServlet</servlet-name>
<servlet-class>com.netease.server.example.web.controller.ServletConfigServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ServletConfigServlet</servlet-name>
<url-pattern>/servlet/ServletConfig</url-pattern>
</servlet-mapping>
从Servlet中获取对应的参数:
首先,拿到ServletConfig对象
然后配置对应的参数值即可
@Override
public void init() throws ServletException {
ServletConfig config = this.getServletConfig();
String v1 = config.getInitParameter(data1);
System.out.println("v1 = " + v1);
String v2 = config.getInitParameter(data2);
System.out.println("v2 = " + v2);
}
NB: do NOT forget to add a doGet() method to handle the response stuff.
不同的Servlet共享的配置信息:ServletContext
Servlet容器在启动的时候,会对每个web应用创建一个对应的ServletContext对象(全局只有一个)
在web.xml中进行ServletContext的配置:
<context-param>
<param-name>globalData1</param-name>
<param-value>123</param-value>
</context-param>
<!-- could be several pairs -->
<!-- no mapping to servlet -->
在任意Servlet中获取配置即可:
ServletContext ctx = this.getServletContext();
String globalValue1 = ctx.getInitParameter("globalData1");
String globalValue2 = ctx.getInitParameter("globalData2");
System.out.println("global value1: " + globalValue1 + "; global value2: " + globalValue2);
如果这些配置是事先不知道的呢?-- ServletContext也支持动态信息-Attribute(Key-Value)
i.e. 通过ServletContext的动态属性,来完成信息的共享
在Servlet a中:ctx.setAttribute(“attribute”,”111”); // set key-value pair
在Servlet b中:String attribute1 = (String) ctx.getAttribute(“attribute”); //get the value of attribute1
如果想要从外部资源里而不是web.xml中读取配置信息呢?
getResource();
getResourceAsStream();
getRealPath();
i.e. 使用ServletContext读取log4j的配置信息
1. getResource();
URL url = ctx.getResource(“/WEB-INF/classes/log4j.properties”); -- import java.net;
-- try catch: MalformedURLException
InputStream in = url.openStream(); -- import java.io;
-- try catch: IOException
写方法String getProperty(String, InputStream);
public static String getPropery(String key, InputStream in) {
Properties props = new Properties();
try {
props.load(in);
} catch (IOException e) {
e.printStackTrace();
}
String value = props.getProperty(key);
return value;
}
调用该方法获取对应的value
String propertyValue = GeneralUtil.getProperty(“log4j.rootLogger”, in);
即可。
完整代码:
public static String getPropery(String key, InputStream in) {
Properties props = new Properties();
try {
props.load(in);
} catch (IOException e) {
e.printStackTrace();
}
String value = props.getProperty(key);
return value;
}
2. getResourceAsStream();
InputStream in = ctx.getResourceAsStream(“/WEB_INF/classes/log4j.properties”);
String p = GeneralUtil.getProperty(“log4j.rootLogger”, in);
3.getRealPath();
String path = ctx.getRealPath(“/WEB-INF/classes/log4j.properties”);
System.out.println(“real path:”+path);
File file = new File(path);
InputStream in = new FileInputStream(file);
// try catch FileNotFoundException
String p = GeneralUtil.getProperty(“log4j.rootLogger”, in);
Servlet配置
web应用程序的基本结构:
webapp:
1.公共资源:通过url可以访问到的静态资源,如css, js, image, html, 不同类型资源分类于不同目录
2. META-INF目录:定义了jar包的源信息,定义了包拓展属性,类加载路径,自定义属性等
3. WEB-INF目录:不提供给用户,无法通过浏览器访问。放置类文件和类所依赖的库
包含两个子目录:classes和lib和一个web.xml文件。classes放置编写的代码和编译后的类文件。lib放置web依赖的jar包。
web.xml部署描述服务,用于描述一个web应用。
web.xml文件:
用于设置web应用程序的组件部署信息。
Servlet容器需要支持部署描述符的所有元素。
web.xml文件中的设置:
1. Servlet声明
<servlet>
<servlet-name>servlet类的名称</servlet-name>
<servlet-class>servlet类的实际路径</servlet-class>
<servlet>
<servlet-mapping>
<servlet-name>和shangm上面对应的类名</servlet-name>
<url-pattern>servlet对外映射的相对路径(一般以/开头)</url-pattern>
<url-pattern>可有多个mapping路径&“*”可做模糊匹配</url-pattern>
</servlet-mapping>
Servlet-mapping匹配规则:
若两个Servlet的url-pattern重复了,则
a. 精确路径匹配,完全匹配;
b. 最长路径匹配,最长前缀匹配(路径匹配最多的);
c. 扩展名匹配;
d. default Servlet;
e. 如果没有default Servlet,则放弃匹配返回报错。
规则从上往下按优先级顺序
i.e.
/hello --a--> Servlet1
/hello/world/index --b -->Servlet3
/admin.jsp --c-->Servlet4
/world --d-->Servlet5
/hello.jsp --c-->Servlet4
/hello/world/hello.jsp --b-->Servlet3
2. ServletConfig配置--位于Servlet元素
<servlet>
<init-param> // 可有多个
<param-name>key</param-name>
<param-value>value</param-value>
</init-param>
<servlet-name>…
……
3. ServletContext配置-全局
<context-param>
<param-name>key</param-name>
<param-value>value</param-value>
</context-param>
4. 若需要在Servlet容器启动时执行操作(init()为找Servlet第一次收到请求时的操作)
“load-on-startup”改变Servlet默认初始化时间--负数/无设置:第一次请求时加载
<servlet>
<load-on-startup>0</load-on-startup>
<servlet-name>…
……
5. 配置自定义错误页面<error-page>
<error-page>
<error-code>404</error-code>
<location>/404.html</location>
</error-page>
更高级的做法:添加exception-type元素捕获一个Java异常类型
6. 若用户在地址栏输入web app路径的url,如:http://localhost:8080/web_project_template/
会出现一个登录页面--index.html页面(首页/欢迎页面)
对应在部署描述中为<welcome-file-list>可包含一个或多个<welcome-file>子元素
指定多个欢迎页面的加载顺序:<welcome-file>在<welcome-file-list>中的顺序
7. 对于静态资源 打开文件or下载文件?
MIME(Multi-purpose Internet Mail Extensions)多用途互联网邮件扩展类型--发展为描述信息内容类型的互联网标准。
--设置某种扩展名文件的打开方式
<mime-mapping>定义扩展文件名映射类型
<extension>
<mime-type>
</mime-mapping>
作业没做!!