一、概述
广义的Servlet指实现了Servlet接口的类,运行在支持Java的服务器上,遵循了服务器能识别的规则,服务器自动根据请求调用对应的servlet进行请求处理。
使用:1.创建普通java类并继承HttpServlet(new-->Servlet可以自动配置)
2.复写service方法
3.Web Root文件夹中的WEB-INF文件中的web.xml中配置servlet
运行流程:浏览器发请求到服务器,服务器根据URL地址在webapps目录中找到项目文件,然后在web.xml中检索对应的servlet,找到后调用执行servlet
URL:http://localhost:8080/project名字/myservlet名字
组成:服务器地址:端口号 / webapps文件中的项目名/servlet的别名(要执行的servlet的)
login.jsp(执行的jsp,action对应servlet)
WEB-INF中web.xml中配置servlet
<!-- 给Tomcat服务器配置servlet程序-->
<servlet>
<servlet-name>HelloServlet</servlet-name><!-- servlet的名字-->
<servlet-class>com.servlet.HelloServlet</servlet-class><!-- servlet在项目中的路径-->
</servlet>
<!-- 给servlet程序配置访问地址-->
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name><!-- servlet的名字-->
<url-pattern>/servlet01</url-pattern><!-- servlet在利用浏览器打开时的别名-->
<!-- 代表http://ip:port/部署时的工程名字/servlet01 -->
</servlet-mapping>
二、Servlet的生命周期
服务器启动web.xml加载进内存,浏览器发起请求,服务器根据URL对比web.xml
生命周期:1.从第一次发请求servlet加载进内存并初始化,到服务器关闭servlet才关闭
2.web.xml配置加载序号时,服务器启动,到服务器关闭。
执行方法的顺序:
- servlet构造器方法
- init初始化方法 (1和2在第一次访问,创建servlet时调用)
- service方法 (3每次访问都调用)
- destroy方法 (web工程停止时调用)
三、Service方法、doGet方法和doPost方法的区别
Service方法: 请求方式为get、post都可以执行,优先调用
注意:在复写的service方法中调用super.service(),
则service方法执行后会根据请求类型调用对应doGet或doPost的方法
(一般不调用父类service,避免没有复写doGet,doPost方法,出现错误)
doGet方法:处理get类型的请求
doPost方法:处理post类型的请求
获取请求方式 String method=req.getMethod(); 可以get和post调用不同方法
四、常见错误类型
404错误:资源未找到
原因:URL中的虚拟项目名称拼写错误,servlet的别名拼写错误
500错误:服务器内部错误
找到servlet,按照路径没找到对应的类
原因:配置web.xml中servlet路径错误,
405错误:请求方式不支持
原因:请求方法和对应servlet中的方法不匹配
五、request 对象
浏览器发请求到服务器,服务器每接收一个请求,就创建一个对象专门存储此次请求的请求数据,服务器在调用servlet时将Request对象作为实参传递给servlet的方法,比如service方法
使用:获取请求行,请求头,用户数据
package servlet;
import java.io.IOException;
import java.util.Enumeration;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/*
* Request对象学习
* 作用:request对象有当前请求的所有信息,由tomcat创建,
* 并作为实参传递给servlet的service方法
* 使用:获取请求行,请求头,用户数据
*
* */
public class RequestServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//获取请求行数据
//1.获取请求方式
String method=req.getMethod();
System.out .println(method);
//2.获取请求URL
StringBuffer url=req.getRequestURL();
System.out .println(url);
/*
*http://127.0.0.1:8080/MyServlet/Method.jsp-->提交
*http://127.0.0.1:8080/MyServlet/req(请求方式为post)
*http://127.0.0.1:8080/MyServlet/req?uname=%E5%BC%A0%E4%B8%89&pwd=123(请求方式为get)
*/
//3.获取协议
String pro=req.getProtocol();
System.out .println(pro);
//获取请求头数据
String value=req.getHeader("User-Agent");//由键名获取值
System.out .println(value);
Enumeration e=req.getHeaderNames();//获取所有键的枚举
while(e.hasMoreElements()){
String name=(String) e.nextElement();
String value2=req.getHeader(name);
System.out .println(name+":"+value2);
}
//获取用户数据
/*
* 请求方式post或get不影响获取数据的方法名,都是req.getParameter("键名")
* 如果键名不存在,返回null
* 要获取同键名不同值的数据用req.getParameterValues("键名");
* 获取所有键名的枚举req.getParameterNames()
* */
String uname=req.getParameter("uname");
String pwd=req.getParameter("pwd");
System.out .println(uname+":"+pwd);
String[] favs=req.getParameterValues("fav");
if(favs!=null){//如果键名不存在会有空指针异常
for(String fav:favs)
{
System.out .println("兴趣:"+fav);
}
}
}
}
六、Response 对象
服务器创建Request对象从浏览器获取请求数据,创建Response对象响应数据到浏览器,
使用:设置响应头,响应实体
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 ResponseServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//获取请求信息
//处理请求
//数据库操作
//响应处理结果
//1.设置响应头
resp.setHeader("service", "my");//(键名,值)键名相同后一个会覆盖前一个
resp.addHeader("service", "my");//(键名,值)键名相同新加一个,不会覆盖
//设置响应编码格式
resp.setHeader("content-type","text/html;charset=utf-8");//编码方式
//HTML,标签被解释执行
//resp.setContentType("text/html;charset=utf-8");
//plain代表普通文本,标签不起作用,原样输出
//resp.setContentType("text/plain;charset=utf-8");
//2.设置响应状态码
//resp.sendError(404, "sorry");
//3.设置响应实体
resp.getWriter().write("<b>响应实体this is resp study<b>");
}
}
七、登录练习
1.创建登陆页面
创建servlet进行响应
2.点击登录
浏览器发请求到服务器
服务器调用对应的servlet处理
3.servlet完成登录校验
连接数据库
浏览器(通过URL)
--->pageServlet(显示表单,用户提交后调用prove)
--->prove(取到用户提交的数据,用业务层loginService处理数据,给用户响应)
--->业务层loginService(处理数据,需要用到数据库,所以调用Dao层)
--->loginDao(连接数据库,匹配数据,结果返回上一层)
servlet流程总结:
1. 浏览器发请求到服务器
2.服务器接收请求就行解析,创建request对象存储请求数据
3.服务器调用对应servlet进行请求处理,并将request对象作为实参传递给servlet的方法
4.servlet方法进行处理
//设置请求编码格式
//设置响应编码格式
//得到请求信息
//处理请求信息
//创建业务层对象
//调用业务层的方法
5.response响应处理结果
1.PageServlet
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 PageServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
/*浏览器访问的第一个页面,提供表单,点击登录调用名为prove的servlet*/
//1.设置响应编码格式
resp.setContentType("text/html;charset=utf-8");
//2.获取请求信息
//3.处理请求
//4.响应处理结果
//(不用JSP)
resp.getWriter().write("<html>");
resp.getWriter().write("<head>");
resp.getWriter().write("</head>");
resp.getWriter().write("<body>");
resp.getWriter().write("<form action='prove' method='post' >");
resp.getWriter().write("用户名:<input type='text' name='uname' value=''/><br>");
resp.getWriter().write("密码:<input type='password' name='pwd' value=''/><br>");
resp.getWriter().write("<input type='submit' value='登录'/><br>");
resp.getWriter().write("</form>");
resp.getWriter().write("</body>");
resp.getWriter().write("</html>");
}
}
2.proveServlet
import java.io.IOException;
import java.sql.*;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import pojo.User;
import service.LoginService;
import service.impl.LoginServiceImpl;
public class Prove extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
/**/
//1.设置编码格式
resp.setContentType("text/html;charset=utf-8");
//2.获得请求数据
String name=req.getParameter("uname");
//重新设置编码格式,使客户端可以提交中文而不乱码
name=new String(name.getBytes("iso8859-1"),"utf-8");
String pwd=req.getParameter("pwd");
System.out.println(name+":"+pwd);
//3.处理请求
//因为数据给业务层,所以要获取业务层对象
LoginService ls=new LoginServiceImpl();
User u=ls.checkLoginService(name, pwd);
System.out.println(u);
//4.给出响应
if(u!=null
){
resp.getWriter().write("登录成功");
System.out.println("成功");
}else
{
resp.getWriter().write("用户名或密码错误");
System.out.println("失败 ");
}
}
}
3.user类
package pojo;
public class User {
private int uid;
private String uname;
private String pwd;
public int getUid() {
return uid;
}
public void setUid(int uid) {
this.uid = uid;
}
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((pwd == null) ? 0 : pwd.hashCode());
result = prime * result + uid;
result = prime * result + ((uname == null) ? 0 : uname.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
User other = (User) obj;
if (pwd == null) {
if (other.pwd != null)
return false;
} else if (!pwd.equals(other.pwd))
return false;
if (uid != other.uid)
return false;
if (uname == null) {
if (other.uname != null)
return false;
} else if (!uname.equals(other.uname))
return false;
return true;
}
public User() {
super();
// TODO Auto-generated constructor stub
}
public User(int uid, String uname, String pwd) {
super();
this.uid = uid;
this.uname = uname;
this.pwd = pwd;
}
}
4.loginservice接口
package service;
import pojo.User;
public interface LoginService {
User checkLoginService(String uname,String pwd);
}
5.loginservice实现
package service.impl;
import dao.LoginDao;
import dao.impl.LoginDaoImpl;
import pojo.User;
import service.LoginService;
public class LoginServiceImpl implements LoginService{
//因为要给dao层,所以创建Dao层对象
LoginDao ld=new LoginDaoImpl();
@Override
public User checkLoginService(String uname, String pwd) {
//可以写规则校验等,
return ld.checkLoginDao(uname, pwd);
}
}
6.loginDao接口
package dao;
import pojo.User;
public interface LoginDao {
User checkLoginDao(String name,String pwd);
}
7.logindao实现
package dao.impl;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import com.mysql.jdbc.Connection;
import pojo.User;
import dao.LoginDao;
public class LoginDaoImpl implements LoginDao{
@Override
public User checkLoginDao(String name, String pwd) {
//连接数据库
//1.导jar包
//声明jdbc对象
Connection conn=null;
PreparedStatement ps=null;
ResultSet rs=null;
//声明数据存储对象
User u=null;
try {
//加载驱动
Class.forName("com.mysql.jdbc.Driver");
//获取连接对象
conn=(Connection) DriverManager.getConnection("jdbc:mysql://localhost:3306/login", "root", "123456");
//创建sql语句
String sql="select * from t_user where uname=? and pwd=?";
//创建sql命令对象
ps=conn.prepareStatement(sql);
//给占位符赋值
ps.setString(1, name);
ps.setString(2, pwd);
//执行
rs=ps.executeQuery();
//遍历执行结果
while(rs.next())
{
u=new User();
u.setUid(rs.getInt("uid"));
u.setUname(rs.getString("uname"));
u.setPwd(rs.getString("pwd"));
}
//关闭连接
//返回
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
rs.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
ps.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return u;
}
}
八、解决乱码
1.用户提交中文
1.1:利用String重新设置编码格式,使客户端可以提交中文而不乱码,每个可能含中文的变量都需要String
name=new String(name.getBytes("iso8859-1"),"utf-8");
1.2:公共配置
get方式:
《步骤1》req.setCharacterEncoding("utf-8");
《步骤2》在tomcat服务器目录下conf文件下找到server.xml文件,配置如下
port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
useBodyEncodingForURI="true" />
post方式: req.setCharacterEncoding("utf-8");
2.返回给用户响应中的中文
//设置编码格式
resp.setContentType("text/html;charset=utf-8");