第九章 servlet
1. Eclipse相关配置
1. 设置为Java视图
点击上放的 Window --> show view --> other -->选中 Java下边的Package Explorer 点击Open
2. 配置Tomcat
同样在 show view中选中 other,搜索Server点击Open
在Server里边会有一个蓝色的连接,双击连接,选中 tomcat8.5
点击next选中自己的tomcat的目录和 JDK 的路径,点击finish
重新在server中双击tomcat 在 Server Locations选中第二个Use
接着把Deploy Path改成 webapps
配置工程,右键tomcat选中add and remove,吧想要的工程添加进去进行了
更改html、CSS、JS等可以不用关闭Tomcat。更改Servlet一定要关闭tomcat
2. 常见HTTP错误
1.404后边存在一个路径
- 表单的action或者链接的href在提交之后没有被web.xml中的url-pattern拦截到
- 从浏览器地址书写的路径错误,路径格式为http://localhost:8080/工程名/页面
- 文件放置的位置出现问题,在eclipse下的页面资源应该放置在WebContent下
- 没有成功部署
2. 404后边没有路径
- tomcat开始失败,原因
- 文件缺失,在安装tomcat之后对tomcat进行增删
- web.xml解析异常,其中节点值必须以 / 开头 节点值必须对应
- 已经开启了一个tomcat,因为只有一个8080 端口,所以默认情况下只能开一个tomcat
3.405
Post提交覆盖doPost,GET提交覆盖doGet,或者method属性拼写错误,注意表单和链接提交默认都是GET,链接无法改动,请求转发跳转前后一致,重定向跳转之后一定是doGet
4.500
出现异常,例如空指针异常等,或者在web.xml中的servlet-class节点中无法找到Servlet实例地址。如果是异常则找第一个自己写的类。
5.常用接口
3.创建Servlet的两种方式
1.继承HttpServlet,并覆盖相应方法
1. 修改web.xml配置文件
首先要打开WEB-INF 中的 web.xml文件
此文件是整个文件中最为重要的一个文件,当打开tomcat时,tomcat会对工作空间中所有的 web.xml进行解析,如果出现解析错误,则tomcat开启失败,只要有一个工程解析错误,就无法工作
<servlet>
<!--
Step3)
此处必须对应servlet-mapping子节点中的
servlet-name节点值,如果不匹配,则无法开启tomcat
-->
<servlet-name>suibianxie</servlet-name>
<!--
Step4)
此节点值为Servlet实例的确切路径,最终找到处理用户请求的
Servlet实例,长按Ctrl或者Command键可以检查此处正确与否,
如果此处为无效地址,则500错误
Can not found class 类名 Exception
-->
<servlet-class>com.etoak.servlet.UserLogin</servlet-class>
</servlet>
<servlet-mapping>
<!--
Step2)
当拦截成功时,读取此处的节点值,到
servlet的子节点servlet-name中读取与之相同的节点值
注意如果全文没有与此节点匹配的servlet-name节点值,则
tomcat无法开启
-->
<servlet-name>suibianxie</servlet-name>
<!--
Step1)
此处为拦截路径,这里监听 表单或者链接
提交的路径,如果拦截失败,则报404错误
如果拦截成功则读取servlet-name的节点值
此处书写的格式为 /拦截路径
-->
<url-pattern>/userlog</url-pattern>
</servlet-mapping>
2.书写实现类
package com.etoak.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.etoak.dao.UserDaoIf;
import com.etoak.dao.UserDaoImpl;
import com.etoak.po.User;
/*
* 一个普通的Java类只要继承了HttpServlet抽象类,则这个类就可以称之为
* Servlet类
*
* */
public class UserLogin extends HttpServlet{
/*
* 此方法专门用来处理post提交的请求
* 没有返回值
* HttpServletRequest:接口,封装了所有提交过来的请求
* HttpServletResponse:接口,封装了所有要发送走的响应
*
* */
@Override
protected void doPost(HttpServletRequest request
, HttpServletResponse response)
throws ServletException, IOException {
/*
* Servlet默认不支持中文,所以我们需要添加中文支持,
* 以下两句为软编码,添加中文支持
* */
//设置响应的编码
/*
* response.setContentType("MIME;charset=编码");
* 注意 MIME:是专门用来提示浏览器按照何种语法解析的设置
* 此处填写了text/html表示提示浏览器根据html语法进行解析
*
* MIME存在数十种写法
* text/html:根据html语法解析
* text/css:根据css语法解析
* text/javascript:根据js语法解析
* text/plain:被浏览识别为字符串
* application/json:根据json语法解析
* image/jpeg:被浏览器识别为一张jpeg格式的图片
*
* 注意!!!此处如果书写错误
* 则浏览器提示下载文件
* */
response.setContentType("text/html;charset=utf-8");
//设置请求的编码
request.setCharacterEncoding("utf-8");
//拿取字符输出流,一般不使用字节流
PrintWriter out = response.getWriter();
//引入dao层
UserDaoIf dao = new UserDaoImpl();
//接受页面表单提交过来的用户名和密码
/*
* 注意这里 request.getParameter("这里对应页面name属性值")
*
* <input type="text" name="对应这里">
* */
String name = request.getParameter("myname");
String pass = request.getParameter("mypass");
System.out.println(name+"\t"+pass);
//使用JDBC技术调用dao层
User u = dao.queryUser(name, pass);
if(u!=null) {
//普通用户登录
if(u.getLevel().equals("0")) {
out.println("欢迎您回来"+u.getName());
out.print(u.getGender().equals("0")?"女士":"先生");
out.println("<hr />");
out.println("以下为普通用户页面结构样式...");
out.close();
return;
}
//管理员登录
if(u.getLevel().equals("1")) {
out.println("欢迎您回来管理员"+u.getName()+"<hr />");
out.println("<a href='showuser'>查看所有普通用户资料</a>");
out.close();
return;
}
//超级管理员登录
if(u.getLevel().equals("2")) {
out.println("超级管理员"+u.getName()+"您好<hr />");
out.println("<a href='showadmin'>查看所有管理员资料</a>");
out.close();
return;
}
return;
}
//动态输出页面
// request.getContextPath():拿取/工程名
// 此处组合成了一个绝对路径 /工程名/XXXX.html
out.println("数据库中查无此人,请您先<a href='"+request.getContextPath()+"/reg.html'>注册</a><hr>");
out.close();
}
}
2.创建Servlet
在servlet包下右键新建,选择other搜索servlet,点击open,创建书写Class Name,点击Next,在下方的拦截地址中改为对应的拦截地址,next,专责需要覆盖的方法
4.Servlet注意点
-
给Servlet添加中文支持
Servlet默认不支持中文,所以我们需要添加中文支持
MIME写法 含义 text/html 根据html语法解析 text/css 根据css语法解析 text/javascript 根据js语法解析 text/plain 被浏览识别为字符串 application/json 根据json语法解析 image/jpeg 被浏览器识别为一张jpeg格式的图片 //设置响应的编码 MIME存在数十种写法,上边写了几种常用的 //response.setContentType("MIME;chaeset=编码"); //此处书写错误,浏览器会提示下载文件注意 response.setContentType("text/html;charset=utf-8"); //设置请求编码 request.setCharacterEncoding("utf-8");
-
方法含义
方法 含义 request.getParameter() 从前端页面根据name获取value request.getContextPath() 拿取 /工程名 request,getParameterValues() 拿取复选框的值,返回String[] -
重定向之后不能再次提交请求问题
在下边这种情况下,重定向之后一定要加return
if(u != null){ response.sendRedirect(request.getContextPath() + "/showadmin"); //return; } response.sendRedirect(request.getContextPath() + "/showlog");
如果在重定向结束之后没有写return语句,会有500异常,Cannoot call sendRedirect() after the response has been committed
5. Servlet两种跳转方式
1.请求转发
浏览器发送请求到Servlet1,Servlet1执行请求转发之后,再讲请求转发到最终目的地Servlet2,由于不再是浏览器亲自发送到到最终目的地,所以浏览器的地址栏显示信息只是跳转前的路径,因为是同义词请求,request范围有效,跳转前是doXXX之后依旧是doXXX
其中一种
request.getRequestDispatcher(“showadmin”).forward(request, response);第一个参数为要跳转的地址
2.重定向
浏览器发送请求到Servlet1,Servlet1返回相应到浏览器,浏览器重新发送请求到Servlet2,由于不再是一次请求,所以request范围失效。由于是浏览器轻自发出请求,所以浏览器的地址栏会变为最终跳转的路径。跳转之前是doXX之后肯定为doGet
路径书写格式可以固定为绝对路径写法
response.sendRedirect("/工程名/拦截路径");
response.sendRedirect("/工程名/xxx.html");
response.sendRedirect("/工程名/xxx.jsp");response.sendRedirect(request.getContextPath() + “/showadmin”)
6. Servlet生命周期
package com.etoak.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/testlife")
public class TestLife extends HttpServlet {
private String code;
/*
* #Servlet的生命周期是怎样的?
Servlet是一个单实例多线程的Java程序
某一个Servlet ~~~~~~~》 通桑
用户 ~~~~~~~》一百多号人
* 构造方法(由于Servlet是单实例多线程的Java程序,仅仅存在一个实例
* 所以构造方法仅仅执行1次)
* |
* |
* init()(此方法称之为初始化方法,一般用来读取一些资源,拿取配置文件中的数据等等
* 类似做了一个准备工作,它也仅仅执行一次)
* |
* |
* service(此方法根据请求的多少,执行多次,一个请求对应线程分配出来的一个
* service(),这个方法会根据请求的类型调用相应的doGet()或者doPost(),service()
* 不推荐我们覆盖,如果覆盖会导致效率低下,并且无法再次自动调用doGet或者doPost)
* |
* |
* doGet||doPost(被service方法调用,根据请求是Get还是Post分配相应的doGet和doPost
* 没有返回值,专门用来书写业务逻辑,执行多次)
* |
* |
* destroy()(当tomcat关闭时,执行此方法,一般用来释放资源等等,仅仅执行一次)
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
*
* 服务器 ======》 蓝石商务中心
* 容器(不严谨的理解为tomcat) ======》 易途科技401和411
* 容器中的工程 ======》 et1912
* 每一个Servlet实例 ======》 每个同学
* 某个Servlet实例 ======》 通桑
* web.xml ======》 座次表
* 客户端 ======》 张老师
*
* */
private static final long serialVersionUID = 1L;
public TestLife() {
System.out.println("我是Servlet的构造方法~~~~~~");
}
public void init() throws ServletException {
System.out.println("我是Servlet的初始化方法init~~~~~~");
/*
* Servlet中四个最常用的接口
*
* 1)ServletConfig
* 封装某个特定Servlet实例的私有信息,书写在哪个Servlet中就只能拿取
* 当前这个Servlet自己的参数
*
* 2)ServletContext
* 封装了整个工程中所有Servlet实例共享的参数
*
* 3)HttpServletRequest
* 封装所有提交过来的请求信息
* 4)HttpServletResponse
* 封装了所有要发送走的响应信息
*
*
* */
/*
* TestLife tl = new TestLife();
* ServletConfig config = tl.getServletConfig();
* 如果不使用this,则根据以上书写
* */
//ServletConfig config = this.getServletConfig();
/*
* 使用ServletConfig也可以拿取ServletContext
* ServletContext application = config.getServletContext();
* */
//System.out.println("类名是~~~~》"+config.getServletName());
//拿取ServletContext
ServletContext application = this.getServletContext();
System.out.println("工程名是~~~~~》"+application.getContextPath());
System.out.println("拿取服务器中web服务器软件中被部署工程的绝对路径~~~~~》"+application.getRealPath("/"));
//拿取web.xml中封装的参数
System.out.println("封装的全局参数是~~~~~》"+application.getInitParameter("东京奥运会"));
//读取配置好的编码类型
code = application.getInitParameter("mycode");
}
public void destroy() {
System.out.println("我是Servlet的销毁方法destroy~~~~~~");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset="+code);
request.setCharacterEncoding(code);
PrintWriter out = response.getWriter();
//接受链接提交过来的值
String value = request.getParameter("etoak");
out.print("我是动态输出的页面,链接传递过来的值是====》"+value);
out.close();
System.out.println("我是负责业务逻辑的doGet()~~~~~~");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request,response);
}
}