对Servlet的理解和认识

Servlet是在服务器端的应用程序,本身不能单独运行,需要配合web应用来完成它的功能和使用,目前我们主要使用servlet完成前后端交互以及访问数据库,使用servlet与html结合就能够搭建出一个完整的web应用项目。可见它的功能还是很强大的。但是servlet尽管很强大,用它去搭建web项目时会感觉很吃力,比如服务器端的servlet处理完一个请求时,需要对客户端完成响应,有的时候需要在后台代码中完成html代码内容的编写,很不方便。而且一个servlet只能映射到一个类中。当web项目的功能很复杂时,需要配置更多的servlet容器完成相应的功能。

servlet的主要工作流程:我们在客户端发出servlet请求到服务器,服务器识别这个请求发送到servlet进行处理,servlet完成处理后发送响应到服务器,服务器根据http协议再讲响应告诉客户端,完成流程。

一:单独的java项目与结合tomcat服务器完成servlet的使用:

1. 使用servlet的jar包:servlet-api.jar,在资源网站中可以轻易的下载得到。

2. 这里以eclipse为例,创建一个java project项目,导入jar包(右击项目-properties-java build path-libraries-add external jars)。

3. 创建HelloServlet类,继承HttpServlet。该类下提供了doGet(处理get请求)、doPost(处理post请求)、service(自动识别请求进行处理,常使用的方法)等主要使用的方法,在该方法中有两个参数分别是request和response。通过以下代码向客户端完成相应。在客户端中打印Hello Servlet和当前时间。

public void doGet(HttpServletRequest request, HttpServletResponse response){
         
        try {
            response.getWriter().println("<h1>Hello Servlet!</h1>");
            response.getWriter().println(new Date().toLocaleString());
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

4. 在项目下配置web.xml文件,新建该文件在web - WEB-INF - web.xml。完成以下配置:

<web-app>
 
    <servlet>
        <servlet-name>HelloServlet</servlet-name>
        <servlet-class>HelloServlet</servlet-class>
    </servlet>
 
    <servlet-mapping>
        <servlet-name>HelloServlet</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>
 
</web-app>

 servlet-name就是给它起得名字,servlet-class就是对应的类,servlet-mapping是对name=HelloServlet这个servlet的映射,url-pattren代表的是当遇见/hello这个请求的时候,就交给这个servlet去处理。

5. 配置服务器读取的编译文件classes:

在WEB-INF下创建classes文件夹,然后项目右键->properties->Java Build Path->Source->右下角的 Brower-> 指定位置是 j2ee/web/WEB-INF/classes。点击OK,因为tomcat启动之后会自动去这个路径找classes文件。

6. 配置tomcat:

将tomcat的sever.xml文件打开后,在下图所示位置添加:

<Context path="/" docBase="e:\\project\\j2ee\\web" debug="0" reloadable="false" />

告诉tomcat应该如何访问这个项目以及把这个项目的路径告诉tomcat

7. 启动tomcat,访问localhost:8080/hello就可以看到servlet完成的响应内容了

二: 对于servlet的一些方法和使用规则介绍

1. 如何获取请求带来的参数:

我们通常可以在html页面中通过form表单或者ajax向服务器发出请求,点击登录时,会发送一个方法为post的login请求,此时也就是会把地址栏变为:localhost:8080/login?name=&password=进行访问服务器,此时服务器会找web.xml中是否有转向该servlet请求的类。

注:post请求时:地址栏不会显示参数,get请求时:地址栏会显示参数。不写时默认为get请求。

<body>
  
<form action="login" method="post">
账号: <input type="text" name="name"> <br>
密码: <input type="password" name="password"> <br>
<input type="submit" value="登录">
</form>
  
</body>

web.xml中配置该servlet,并新建Login类,在该类中:

public class Login extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        String name = request.getParameter("name");
        String password = request.getParameter("password");
  
        System.out.println("name:" + name);
        System.out.println("password:" + password);
    }
}

通过request.getParameter(“参数的名字”)获取参数的值。此时我们就能在tomcat的console中看到打印的参数值了。这个请求的流程强调一下,理解很关键:客户端通过form提交post请求---服务器在web.xml中发现了/login对应的servlet---跳转到Login类中找寻doPost方法,在该方法中处理。

2. servlet如何对客户端的请求作出相应:

那我们再增加一个判断,在Login的doPost方法中判断一下客户端传来的账号密码是否正确,然后告诉客户端你输入的对不对。

通过response对象写入html内容,完成响应。代码如下:

protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
  
        String name = request.getParameter("name");
        String password = request.getParameter("password");
        String html = null;
        if ("root".equals(name) && "root".equals(password))
            html = "<div style='color:green'>success</div>";
        else
            html = "<div style='color:red'>fail</div>";
        PrintWriter pw = response.getWriter();//通过response的getWriter创建PrintWriter对象
        pw.println(html);//根据这个response生成html 字符串,然后再通过HTTP协议,把这个html字符串,回发给浏览器,浏览器再根据HTTP协议获取这个html字符串,并渲染在界面上。
  
    }

此时客户端中回显示:

 3. service()方法:service方法会自动识别post或者get请求,一般都用这个的多。

4. 中文乱码问题:html页面中:<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

java代码中:如果是参数是中文的,对参数进行编解码设置:request.setCharacterEncoding("UTF-8");

                     如果要返回中文内容:设置html内容格式:response.setContentType("text/html;charset=UTF-8");

就完成了中文乱码问题。

5. servlet的生命周期:

在此周期中:构造方法(实例化)和init()(初始化)方法都只会执行一次 ,然后在调用service方法,完成之后调用destory()摧毁,变成可回收对象等待GC回收。

6. 跳转: 准备两个html页面,success和fail,内容只显示成功和失败两个字就好。我们用来验证登录的账号密码是否正确然后完成跳转。servlet的跳转分为服务器跳转和客户端跳转。

服务器跳转:在service方法中判断完了之后,直接在服务器中调到指定的文件中,然后响应在客户端中。

客户端跳转:service方法中判断完了,告诉客户端下一步去访问谁,客户端收到该响应后,再次去访问服务器,服务器再把它访问的页面返回给它。

代码如下:

protected void service(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
 
        String name = request.getParameter("name");
        String password = request.getParameter("password");
 
        if ("admin".equals(name) && "admin".equals(password)) {
            request.getRequestDispatcher("success.html").forward(request, response);//这是服务器端跳转
        }
        else{
            response.sendRedirect("fail.html");//客户端跳转,重定向
        }
 
    }

7. servlet的自启动:随着tomcat的启动,自动初始化。即访问init()方法。完成一些初始化的工作。

告诉服务器谁需要自启动:在web.xml文件中添加<load-on-startup>10</load-on-startup>,10代表启动的优先级,越小越高。

    <servlet>
        <servlet-name>HelloServlet</servlet-name>
        <servlet-class>HelloServlet</servlet-class>
        <load-on-startup>10</load-on-startup>
    </servlet>
 
    <servlet-mapping>
        <servlet-name>HelloServlet</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>

在该类中重写public void init(ServletConfig config) {业务代码} 

 8. 其他:

response的301或者302客户端跳转、response设置不使用缓存、如何上传文件等方法,敬请了解。 

二:动态WEB项目:

1. 创建,导包:创建Dynamic Web Project,导入jar包到WebContent/WEB-INF/lib 路径下,WEB-INF创建web.xml文件,配置tomcat并部署在tomcat中。启动tomcat。

注:类文件会被输出到build里,而不是WEB-INF/classes目录下;

WebContent会被整个复制到 E:\project\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\j2ee 这个位置下面去,Eclipse中启动的tomcat其实是访问的这个位置。所以当WebContent里的内容比较多的时候,就会花较长时间复制;

tomcat启动失败:可能是端口被占用或者该tomcat已经启动了;

选好tomcat路径后无法点击finish,解决办法:

如何将普通的java project项目变为动态web项目:

右键项目j2ee->properties->Project Facets->Convert to faceted form...

勾选Dynamic Web Module

勾选之后,会出现 Furthe configuration available ..., 点击

动态web项目的默认内容目录是WebContent,而 j2ee这个项目的对应目录是 web, 所以这里要输入web 

OK

三:使用servlet完成与数据库的交互。也就是对数据库进行增删改查。

我们创建一个小demo,以增加英雄为例,首先我们在本地数据库(用的mysql)中创建test数据库,并新建表hero,分别有以下字段,id为自增长。

 我们通过html页面完成对该数据库表的操作。

1. 新建addHero.html页面。简单设置为姓名,血量,伤害input框,并设置新增按钮提交form表单,form表单action指向AddHero

 2. 设置web.xml添加AddHero的servlet的配置,映射向AddHero.java,然后我们需要新建Hero.java实体类,定义id/name/hp/damage/并且有get/set方法。然后新建HeroDao类,提供JDBC数据库连接、增删改查SQL语句的执行。具体HeroDao.java如下:

package dao;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

import bean.Hero;

public class HeroDao {


//无参构造方法,在实例化的时候就已经加载了JDBC类。
	public HeroDao() {
		try {
			Class.forName("com.mysql.jdbc.Driver");
		} catch (ClassNotFoundException e) {
			// TODO: handle exception
			e.printStackTrace();
		}
	}

//设置公共方法连接数据库	
	public Connection getConnection() throws SQLException {
		return DriverManager.getConnection("jdbc:mysql://localhost:3306/test","root","root");
	}
	
//获取总条数
	public int getTotal() {
		int total = 0;
		try(Connection c = getConnection();Statement s = c.createStatement()) {
			String sql = "select count(*) from hero";
			
			ResultSet rs = s.executeQuery(sql);
			while(rs.next()) {
				total = rs.getInt(1);
			}
			System.out.println("total:" + total);
		} catch (Exception e) {
			// TODO: handle exception
		}
		return total;
	}
	
//新增
	public void add(Hero hero) {
		String sql = "insert into hero values(null,?,?,?)";
		 try (Connection c = getConnection(); PreparedStatement ps = c.prepareStatement(sql);) {
			  
	            ps.setString(1, hero.name);
	            ps.setFloat(2, hero.hp);
	            ps.setInt(3, hero.damage);
	  
	            ps.execute();
	  
	            ResultSet rs = ps.getGeneratedKeys();
	            if (rs.next()) {
	                int id = rs.getInt(1);
	                hero.id = id;
	            }
	        } catch (SQLException e) {
	  
	            e.printStackTrace();
	        }
	}
	
	
//修改	
	public void update(Hero hero) {
		  
        String sql = "update hero set name= ?, hp = ? , damage = ? where id = ?";
        try (Connection c = getConnection(); PreparedStatement ps = c.prepareStatement(sql);) {
  
            ps.setString(1, hero.name);
            ps.setFloat(2, hero.hp);
            ps.setInt(3, hero.damage);
            ps.setInt(4, hero.id);
  
            ps.execute();
  
        } catch (SQLException e) {
  
            e.printStackTrace();
        }
  
    }

//删除	
	 public void delete(int id) {
		  
	        try (Connection c = getConnection(); Statement s = c.createStatement();) {
	  
	            String sql = "delete from hero where id = " + id;
	  
	            s.execute(sql);
	  
	        } catch (SQLException e) {
	  
	            e.printStackTrace();
	        }
	 }
	 
//根据ID获取某条数据	 
	    public Hero get(int id) {
	        Hero hero = null;
	        try (Connection c = getConnection(); Statement s = c.createStatement();) {
	  
	            String sql = "select * from hero where id = " + id;
	  
	            ResultSet rs = s.executeQuery(sql);
	  
	            if (rs.next()) {
	                hero = new Hero();
	                String name = rs.getString(2);
	                float hp = rs.getFloat("hp");
	                int damage = rs.getInt(4);
	                hero.name = name;
	                hero.hp = hp;
	                hero.damage = damage;
	                hero.id = id;
	            }
	  
	        } catch (SQLException e) {
	  
	            e.printStackTrace();
	        }
	        return hero;
	    }

//配合下面有参的方法完成对数据库列表的查询	    
	    public List<Hero> list() {
	        return list(0, Short.MAX_VALUE);
	    }
	  
	    public List<Hero> list(int start, int count) {
	        List<Hero> heros = new ArrayList<Hero>();
	  
	        String sql = "select * from hero order by id asc limit ?,? ";
	  
	        try (Connection c = getConnection(); PreparedStatement ps = c.prepareStatement(sql);) {
	  
	            ps.setInt(1, start);
	            ps.setInt(2, count);
	  
	            ResultSet rs = ps.executeQuery();
	  
	            while (rs.next()) {
	                Hero hero = new Hero();
	                int id = rs.getInt(1);
	                String name = rs.getString(2);
	                float hp = rs.getFloat("hp");
	                int damage = rs.getInt(4);
	                hero.id = id;
	                hero.name = name;
	                hero.hp = hp;
	                hero.damage = damage;
	                heros.add(hero);
	            }
	        } catch (SQLException e) {
	  
	            e.printStackTrace();
	        }
	        return heros;
	    }
	
}

 3. 在AddHero.java中,集成httpservlet类,方法service,获取前台input传来的参数,放在herod对象中,将该对象作为参数放入HeroDao的add方法中,执行该方法。完成数据库的添加。最终客户端跳转到heroList页面中。显示已经添加的信息。代码如下:

public class AddHero extends HttpServlet {
	protected void service(HttpServletRequest request,HttpServletResponse response) throws ServletException,IOException {
		request.setCharacterEncoding("UTF-8");
		response.setContentType("text/html;charset=UTF-8");
		
		Hero hero = new Hero();
		hero.setName(request.getParameter("name"));
		hero.setHp(Integer.parseInt(request.getParameter("hp")));
		hero.setDamage(Integer.parseInt(request.getParameter("damage")));
		HeroDao hd = new HeroDao();
		hd.add(hero);
		
		response.sendRedirect("/j2ee_1/heroList");
	}

}

4. heroList.java中,用table将数据库中的数据展示出来,用servlet写html页面内容,传给客户端进行显示,代码如下:

public class HeroList extends HttpServlet {
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException,IOException {
		response.setContentType("text/html;charset=UTF-8");
		
		List<Hero> heros = new HeroDao().list();//获取数据库中所有数据列表
		
		StringBuffer sb = new StringBuffer();//完成html页面内容设置
		sb.append("<table align='center' border='1' cellspacing='0'>\r\n");
		sb.append("<tr><td>id</td><td>name</td><td>hp</td><td>damage</td><td>删除</td><td>修改</td></tr>\r\n");
		
//占位符的使用%d%s%f...
		String trFormat = "<tr><td>%d</td><td>%s</td><td>%f</td><td>%d</td><td><a href='delHero?id=%d'>删除</a></td><td><a href='editHero?id=%d'>修改</a></td></tr>\r\n";
	
//将数据库中的数据遍历显示在table中。	
		for (Hero hero : heros) {
			String tr = String.format(trFormat, hero.getId(),hero.getName(),hero.getHp(),hero.getDamage(),hero.getId(),hero.getId());
			sb.append(tr);
		}
		sb.append("</table>");
//servlet告诉客户端显示这些东西。
		response.getWriter().write(sb.toString());;
	}

}

注:href="delHero?id=%d"herf也可以请求servlet。

 4. 删除、修改内容同理,这就是使用servlet完成对数据库的操作。

5. servlet还可以将html页面中的json数据传递到后台,以及将后台中的json数据发送到页面中显示,以对象的形式传递。

6. 接下来学习使用jsp。

本人声明:以上学习来自how2j.cn的学习笔记。如有侵权,请联系本人删除。

猜你喜欢

转载自blog.csdn.net/qq_41908550/article/details/83153232