Servlet

什么是Servlet

Servlet是基于Java技术的Web组件,由容器管理并产生动态的内容。Servlet引擎作为WEB服务器的扩展提供支持Servlet的功能。Servlet与客户端通过Servlet容器实现的请求/响应模型进行交互。

注意:
Servlet不是从命令行启动的,而是由包含Java虚拟机的Web服务器进行加载

Servlet是按照Servlet规范编写的Java类。

Servlet应用请求/响应模型,扩展了服务器的功能。

Servlet是WEB应用程序中的一个组件。

Servlet是在JSP之前就存在的运行在服务端的一种Java技术,它是用Java语言编写的服务器端程序在JSP技术出现之前,Servlet被广泛地应用来开发动态的Web应用程序.如今在J2EE项目的开发中,Servlet仍然被广泛的使用。

Servlet是一种独立于平台和协议的服务器端的Java技术,可以用来生成动态的Web页面与传统的CGI(公共网关接口)和许多其他类似CGI技术相比,Servlet具有更好的可移植性、更强大的功能,更少的投资,更高的效率,更好的安全性等特点。

Servlet的运行过程

⒈、客户端发送请求至服务器端;

⒉、服务器端根据web.xml文件中的Servlet相关配置信息,将客户端请求转发到相应的Servlet

⒊、 Servlet引擎调用Service()方法,根据request对象中封装的用户请求与数据库进行交互,返回数据之后,Servlet会将返回的数据封装到response对象中;

⒋、 Servlet生成响应内容并将其传给服务器。响应内容动态生成,通常取决于客户端的请求

⒌、 服务器将响应返回给客户端

Servlet的生命周期

1、 加载和实例化;在第一次请求Servlet时,Servlet容器将会创建Servlet实例;

2、 初始化;Servlet容器加载完成Servlet之后,必须进行初始化,此时,init方法将被调用;

3、Servlet初始化之后,就处于响应请求的就绪状态,此时如有客户端请求发送,就会调用Servlet实例的service()方法,并且根据用户的请求方式,调用doPost或者doGet方法;

4、 最后,Servlet容器负责将Servlet实例进行销毁,调用destroy方法实现;

对于更多的客户端请求,Server创建新的请求和响应对象,仍然激活此Servlet的service()方法,将这两个对象作为参数传递给它。如此重复以上的循环,但无需再次调用init()方法。
一般Servlet只初始化一次(只有一个对象),当Server不再需要Servlet时(一般当Server关闭时),Server调用Servlet的Destroy()方法。

在这里插入图片描述

实例演示

html代码–客户端浏览器

1、注册页面

<html>
<head>
    <title>注册页面</title>
</head>
<body>
<form action="/Create">
    <p>用户名:<input type="text" name="user"></p>
    <p>密码:<input type="password" name="pwd"></p>
    <p>确认密码:<input type="password" name="cfmPwd"></p>
    <p><input type="submit" name="注册"></p>
</form>
</body>
</html>

2、登录页面

<html>
<head>
    <title>登录首页</title>
</head>
<body>
<form action="/doLogin">
    <p>请输入用户名:<input type="text" name="user"></p>
    <p>请输入密码:<input type="password" name="pwd"></p>
    <p><input type="submit"></p>
</form>
</body>
</html>

3、配置web.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <servlet>
        <servlet-name>userServlet</servlet-name>
        <servlet-class>servlet.UserServlet</servlet-class>
    </servlet>
     <servlet-mapping>
         <servlet-name>userServlet</servlet-name>
         <url-pattern>/Create</url-pattern>
     </servlet-mapping>
</web-app>

配置文件

1、User类

public class User {
    private int user_id;
    private String user_name;
    private String password;

    @Override
    public String toString() {
        return "User{" +
                "user_id=" + user_id +
                ", user_name='" + user_name + '\'' +
                ", password='" + password + '\'' +
                '}';
    }

    public int getUser_id() {
        return user_id;
    }

    public void setUser_id(int user_id) {
        this.user_id = user_id;
    }

    public String getUser_name() {
        return user_name;
    }

    public void setUser_name(String user_name) {
        this.user_name = user_name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

2、UserDao接口

public interface UserDao {
    //注册
    boolean createUser(String username,String password);
    //登录
    boolean login(String username,String password);
    //根据用户名查询数据库是否有重复用户
    boolean QueryUserByName(String username);

    //展示所有用户
    ArrayList<User> querAll();
    //修改密码
    void changePassword(String username,String password);
    //删除用户
    void deleteUserById(String username,String password);
}

3、UserDao接口的实现类

public class UserDaoImpl extends BaseDAOImpl implements cn.kgc.kb11.dao.impl.UserDao {
    private final String Driver= "com.mysql.jdbc.Driver";
    private final String url="jdbc:mysql://localhost/bank";
    private final String name="root";
    private final String pwd="1";
    @Override
    public boolean createUser(String username, String password) {
        String sql="insert into user(user_name,password) values(?,?)";
        getConn(Driver,url,name,pwd);
        return  update(sql,username,password);
    }

    @Override
    public boolean login(String username, String password) {
        String sql="select * from user where user_name=? and password=?" ;
        getConn(Driver,url,name,pwd);
        query(sql,username,password);
        try {
            if (getRs().next()) {
                   return true;
                }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return false;
    }

    @Override
    public boolean QueryUserByName(String username) {
        String sql="select * from user where user_name=?";
        getConn(Driver,url,name,pwd);
        query(sql,username);
        try {
            if (getRs().next()) {
                return true;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return false;
    }

    @Override
    public ArrayList<User> querAll() {
        return null;
    }

    @Override
    public void changePassword(String username, String password) {

    }

    @Override
    public void deleteUserById(String username, String password) {

    }
}

4、BaseDao接口

public interface BaseDAO {
    void getConn(String driver,String url,String user,String pwd);
    void query(String sql,String... params);
    boolean update(String sql,String... params);
    void close();
}

5、BaseDao接口的实现类

public class BaseDAOImpl implements BaseDAO {
    private Connection conn;
    private PreparedStatement pst;
    private ResultSet rs;

    public ResultSet getRs() {
        return rs;
    }

    @Override
    public void getConn(String driver, String url, String user, String pwd) {
        try {
            Class.forName(driver);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        try {
            conn = DriverManager.getConnection(url,user,pwd);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void query(String sql, String... params) {
        try {
            pst=conn.prepareStatement(sql);
            for (int i = 0; params!=null && i < params.length; i++) {
                pst.setObject(i+1,params[i]);
            }
            rs=pst.executeQuery();
        }
        catch (SQLException e) {
            e.printStackTrace();
        }


    }

    @Override
    public boolean update(String sql, String... params) {
        int num=0;
        try {
            pst=conn.prepareStatement(sql);
            for (int i = 0; params!=null && i < params.length; i++) {
                pst.setObject(i+1,params[i]);
            }
            num=pst.executeUpdate();
        }
        catch (SQLException e) {
            e.printStackTrace();
        }
        return num>0;
    }

    @Override
    public void close() {
        try {
            if (rs!=null)
                rs.close();
            if (pst!=null)
                pst.close();
            if (conn!=null)
                conn.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

6、UserService接口

public interface UserService {
    boolean register(String username,String password,String cfmPwd);
    boolean login(String username,String password);
    ArrayList<User> queryALL();
    void modify(String username,String password);
    void delete(String username,String password);
}

7、UserService接口的实现类

public class UserServiceImpl implements UserService {
    UserDao dao=new UserDaoImpl();

    @Override
    public boolean register(String username, String password,String cfmPwd) {
        if (username==null ||password==null||cfmPwd==null)
            return false;
        boolean exists=dao.QueryUserByName(username);
        if (exists)
            return false;
        if (!password.equals(cfmPwd))
            return false;
        if ("mahuateng".equals(username))
            return false;
        return dao.createUser(username,password);
    }

    @Override
    public boolean login(String username, String password) {
        if (username==null ||password==null)
            return false;
        boolean exists=dao.login(username,password);
        return exists;
    }

    @Override
    public ArrayList<User> queryALL() {
        return null;
    }

    @Override
    public void modify(String username, String password) {

    }

    @Override
    public void delete(String username, String password) {

    }
}

servlet处理过程

1、UserServlet类

public class UserServlet extends HttpServlet {
    UserService service=new UserServiceImpl();
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//        String name=req.getParameter("user");
//////        String pwd=req.getParameter("pwd");
//////        String cfmPwd=req.getParameter("cfmPwd");
//////        boolean isSuccess = service.register(name, pwd, cfmPwd);
////////        System.out.println(isSuccess?"注册成功":"注册失败");
//////        //页面跳转
//////        if (isSuccess){
//////            resp.sendRedirect("/login/home.jsp");
//////        }else {
//////            req.getRequestDispatcher("/login/createUser.jsp").forward(req,resp);
//////        }
//////    }
        String name=req.getParameter("user");
        String pwd=req.getParameter("pwd");
        boolean isSuccess = service.login(name, pwd);
        if (isSuccess){
            req.getRequestDispatcher("/login/doLogin.jsp").forward(req,resp);
        }else{
            resp.sendRedirect("/login/home.jsp");
        }
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.service(req, resp);
    }
}

Servlet如何同时处理多个请求?

Servlet采用多线程来处理多个请求的同时访问。Servlet容器通过线程池来管理维护服务请求。所谓线程池,相当于数据库连接池,实际上是等待执行代码的一组线程,叫做工作者线程。Servlet容器通过一个调度线程来管理工作者线程。

1、当容器收到一个Servlet的访问请求,调度者线程就从线程池中选出一个工作者线程,将用户请求传递给该线程,然后由该线程处理Servlet的service()方法;

2、 当这个线程在执行的时候,容器收到一个新的请求,调度者线程再次从线程池中选出一个新的工作者线程;

3、当容器同时收到对同一个Servlet的多个请求时,那么Servlet的service方法将在多线程中并发执行。

注:

1.Servlet容器默认采用单实例多线程的方式来处理请求。这样减少了产生Servlet实例的开销,提升了对请求的响应时间;
2.对于Tomcat容器来讲,可以在其server.xml中通过中设置线程池中的线程数目。

如何开发线程安全的Servlet?

Servlet容器采用多线程来处理请求,提高性能的同时也造成了线程安全问题。要开发线程安全的Servlet应该从一下几个方面进行:
1、变量的线程安全; 多线程并不共享局部变量,所以我们要尽可能的在Servlet中使用局部变量;

2、代码块的线程安全; 使用同步块Synchronized,防止可能调用的代码块;但是要注意的是,要尽可能得缩小同步代码的方范围,不要在service方法和响应方法上直接使用同步,这会严重影响性能。

3、属性的线程安全; ServletContext,HttpSession,ServletRequest对象中属性;

4、使用同步集合; 使用Vector代替ArrayList,使用HashTable代替HashMap;

5、不要在Servlet中创建自己的线程来完成某个功能; Servlet本身就是多线程的,如果再创建新的线程,将会导致线程执行复杂化,出现线程安全问题;

6、在多个Servlet中,对外部对象,比如:文件;进行修改操作一定要加锁,做到互斥访问;

总结

一个servlet就是Java编程语言中的一个类,它被用来扩展服务器的性能,服务器上驻留着可以通过“请求-响应”编程模型来访问的应用程序。Servlet通过解析http请求,取得客户端的参数来进行下一步操作。其实简单来说,servlet就是一个控制器,取参数,调用业务逻辑。
而在.net 中HttpHandler是一个HTTP请求的真正处理中心,也正是在这个HttpHandler容器中,ASP.NET Framework才真正地对客户端请求的服务器页面做出编译和执行,并将处理过后的信息附加在HTTP请求信息流中再次返回到HttpModule中。

今天的分享就到这里,谢谢!

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐