全面学习Servlet与JSP入门与提高(第一篇)

这里我将和大家一起学习和回顾整个servlet和jsp技术,由于这部分学习的东西较多,我把这块分成了三篇,每一篇都从简到难地安排了一些小知识点,东西是当时我老师讲的,现在将知识点都整理下来,供大家一起讨论学习,也方便以后自己复习。如果有不对的地方欢迎大家指正。
以下是这篇大该的纲要及详细内容:

1.servlet简介,开发步骤…(之前写的一篇,这里不再写了)
2.HTTP协议的讲解,添加用户
3.重定向,Dao的概念及编写
4.JSP概念,java代码片段,html转jsp…
5.转发,相对路径与绝对路径

<2>.HTTP协议的讲解,添加用户

1.http协议 (了解)

(1)什么是http协议?

是一种网络应用层协议、规定了浏览器与web服务器之间如何通信以及相应的数据包的格式。

1)如何通信?
step1.建立连接
step2.发送请求
step3.发送响应
step4.关闭连接

这样做的好处是,服务器可以利用有限的连接数为尽可能
多的请求服务。

在这里插入图片描述

2)数据包的格式

a.请求数据包

请求行(请求方式 请求资源路径 协议和版本)
若干消息头
	消息头是一些键值对,使用": "隔开,通信的双方可以借助于消息头来传递一些特定的信息,比如浏览器可以发送"user-agent"消息头,告诉服务器浏览器的类型和版本。
实体内容
	如果请求类型为get,实体内容为空。
	只有当请求类型为post时,实体内容才会有数据。

b.响应数据包

状态行(协议类型和版本 状态码 状态描述)
	注:
		状态码是一个三位数字,表示服务器处理请求的一种状态,常见状态码如下:
		200: 正常
		500: 系统出错
		404: 请求路径出错
若干消息头
	服务器也可以发送一些消息头给浏览器,比如,发送content-type消息头,告诉浏览器,服务器返回的数据类型(包括编码)

c.实体内容

程序的处理结果,浏览器会解析出来,生成相应的页面。
(2)两种请求方式
1)哪些情况下,浏览器会发送get请求?
a.直接在浏览器地址栏输入地址。
b.点击链接。
c.表单的默认提交方式。
2)get请求的特点
a.会将请求参数显示在浏览器地址栏,不安全。
注:
	因为有些网络设备(比如路由器)会记录访问地址。
b.会将请求参数添加到请求资源路径的后面,只能提交少量的数据给服务器。
注:
	因为请求行大约只能存放2k左右的数据。
3)哪些情况下,浏览器会发送post请求
a.设置表单的method属性值为"post"。	
4)post请求的特点
a.不会将请求参数显示在浏览器地址栏,相对安全。
注:
	http协议并不会对数据进行加密,所以,对于敏感数据,需要进行加密处理(使用https协议)。

b.将请求参数添加到了实体内容里面,可以提交大量的数据给服务器。

2.Servlet输出中文需要注意的问题

(1)为什么会产生乱码?

因为out.println方法默认会使用"iso-8859-1"来编码。

(2)如何解决?

response.setContentType(“text/html;charset=utf-8”);

3.读取请求参数值

(1)String getParameter(String paramName)
a.请求参数名(paramName)要与实际传递过来的请求参数名一致,否则会获得null值。
b.提交表单时,如果不填写任何数据,会获得""。
(2)String[] getParamterValues(String paramName)
a.当有多个请求参数名相同时,使用此方法。
b.对于多选框,如果不选择任何选项,会获得null值。

4.表单包含有中文参数值,如何处理?

(1)为什么会产生乱码?

提交表单时,浏览器会对表单中的中文参数值进行编码,比如
使用utf-8来编码,服务器端默认会使用iso-8859-1来解码,所以会产生乱码。

注:
	浏览器会按照打开该表单所在页面时的字符集来编码。
(2)如何解决?
1)post请求

request.setCharacterEncoding(“utf-8”);

注:
	此行代码要添加到所有的getParameter方法的最前面。
	只针对post请求有效。
2)get请求

修改tomcat的配置文件(server.xml)

<Connector URIEncoding="utf-8"/>
注:
	只针对get请求有效。

5.访问数据库

step1.导包

<dependencies>
	<dependency>
		<groupId>mysql</groupId>
		<artifactId>mysql-connector-java</artifactId>
		<version>5.1.6</version>
	</dependency>

	<dependency>
		<groupId>commons-dbcp</groupId>
		<artifactId>commons-dbcp</artifactId>
		<version>1.4</version>
	</dependency>
</dependencies>

step2.添加jdbc.properties文件。

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jsd1807db?useUnicode=true&characterEncoding=UTF-8
username=root
password=root

step3.添加DBUtils类。

public class DBUtils {
	private static String driver;
	private static String url;
	private static String username;
	private static String password;
	
	private static BasicDataSource dataSource;
	
	static {
		Properties prop = new Properties();
		InputStream ips = DBUtils.class
			.getClassLoader()
			.getResourceAsStream("jdbc.properties");
		try {
			prop.load(ips);
			driver = prop.getProperty("driver");
			url = prop.getProperty("url");
			username = prop.getProperty("username");
			password = prop.getProperty("password");
		
			//创建数据源对象
			dataSource = 
					new BasicDataSource();
			dataSource.setDriverClassName(driver);
			dataSource.setUrl(url);
			dataSource.setUsername(username);
			dataSource.setPassword(password);
			dataSource.setInitialSize(3);
			dataSource.setMaxActive(3);
		
		} catch (IOException e) {
			e.printStackTrace();
		}finally {
			try {
				ips.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
	}
	public static Connection getConn() 
			throws Exception {
		return dataSource.getConnection();
	}
	public static void close(Connection conn,
			Statement stat, ResultSet rs) {
		try {
			if(rs!=null) {
				rs.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		try {
			if(stat!=null) {
				stat.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		try {
			if(conn!=null) {
				//打开自动提交
				conn.setAutoCommit(true);
				conn.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
			}
		}
	}

step4.添加一张表(t_user)

create table t_user(
	id int primary key auto_increment,
	username varchar(50) unique,
	password varchar(20),
	email varchar(30)
);

step5.在service方法里面,使用jdbc api访问数据库

public class AddUserServlet extends HttpServlet{
	@Override
	protected void service(
			HttpServletRequest request,
			HttpServletResponse response)
			throws ServletException, 
			IOException {
		
		//处理表单中文参数值的问题
		request.setCharacterEncoding("utf-8");
		
		/*
		 * 这行代码的作用:
		 * 1.设置content-type消息头的值。
		 * 2.out.println方法在输出时,会使用
		 * charset指定的字符集来编码。
		 */
		response.setContentType(
				"text/html;charset=utf-8");
		PrintWriter out = 
				response.getWriter();
		
		//读取用户信息
		String username = 
				request.getParameter("username");
		String pwd = 
				request.getParameter("pwd");
		String email = 
				request.getParameter("email");
		
		//将用户信息插入到数据库
		Connection conn = null;
		PreparedStatement ps = null;
		try {
			conn = DBUtils.getConn();
			String sql = "INSERT INTO t_user "
					+ "VALUES(null,?,?,?)";
			ps = conn.prepareStatement(sql);
			ps.setString(1, username);
			ps.setString(2, pwd);
			ps.setString(3, email);
			ps.executeUpdate();
			out.println("添加成功");
			
		} catch (Exception e) {
			/*
			 * step1.记日志(保留现场)
			 * 注:
			 * 	 在实际项目中,经常需要将异常
			 * 信息写到文件里面。
			 */
			e.printStackTrace();
			/*
			 * step2.看异常能否恢复,如果
			 * 异常不能够恢复(比如数据库服务
			 * 停止、网络中断等等,这样的异常
			 * 我们一般称之为系统异常),则提示
			 * 用户稍后重试;
			 * 如果能够恢复,则立即恢复。
			 */
			out.println("系统繁忙,稍后重试");
			
		}finally {
			DBUtils.close(conn, ps, null);
			}
		}
	}

<3>.重定向,Dao的概念及编写

1.重定向

(1)什么是重定向?

服务器通知浏览器向某个地址发送请求。

注:
	服务器可以发送302状态码和Location消息头(该消息头的值是一个地址,一般称之为重定向地址)给浏览器,浏览器收到之后,会立即向重定向地址发送请求。

在这里插入图片描述

(2)如何重定向?

response.sendRedirect(String url);

注:
	url是重定向地址。
	容器在重定向之前,会清空response对象上存放的所有数据。
(3)特点

a.重定向之后,浏览器地址栏的地址会发生改变。

b.重定向的地址是任意的。

2. DAO (Data Access Object)

(1)DAO是什么?

是一个封装了数据访问逻辑的对象。

(2)如何写一个DAO?

step1.写一个java类(一般称之为实体类)。

注:
	该类与要访问的表的结构保持一致,即表有哪些字段,该类要有与之对应的属性,属性类型要与表的字段类型匹配。
	我们可以将记录中保存的信息添加到实体对象里面,方便处理。
public class User {
		private int id;
		private String username;
		private String pwd;
		private String email;
	
		@Override
		public String toString() {
			return "User [id=" + id + ", username=" + username + ", pwd=" + pwd + ", email=" + email + "]";
		}
	
		public int getId() {
			return id;
		}
		public void setId(int id) {
			this.id = id;
		}
		public String getUsername() {
			return username;
		}
		public void setUsername(String username) {
			this.username = username;
		}
		public String getPwd() {
			return pwd;
		}
		public void setPwd(String pwd) {
			this.pwd = pwd;
		}
		public String getEmail() {
			return email;
		}
		public void setEmail(String email) {
			this.email = email;
		}
	}

step2.写一个java类,提供一些访问数据库的方法。

public class UserDAO {
		/**
		 * 查询出所有用户的信息。
		 * 注:
		 * 关系数据库里面存放的是一条条记录,而java是面向对象的语言。在设计DAO时,我们经常将查询到的记录转换成 一个对应的java对象。
		 */
		public List<User> findAll() 
				throws Exception{
			List<User> users = 
					new ArrayList<User>();
			Connection conn = null;
			PreparedStatement stat = null;
			ResultSet rs = null;
			try {
				conn = DBUtils.getConn();
				String sql = 
						"SELECT * FROM t_user";
				stat = conn.prepareStatement(sql);
				rs = stat.executeQuery();
				while(rs.next()) {
					int id = rs.getInt("id");
					String username = 
							rs.getString("username");
					String pwd = 
							rs.getString("password");
					String email = 
							rs.getString("email");
					User user = new User();
					user.setId(id);
					user.setUsername(username);
					user.setPwd(pwd);
					user.setEmail(email);
					users.add(user);
				}
			} catch (Exception e) {
				e.printStackTrace();
				throw e;
			}finally {
				DBUtils.close(conn, stat, rs);
			}
			return users;
		}
	}
(3)DAO的优点

a.DAO封装了数据访问逻辑,调用者不用关心数据访问逻辑是如何实现的。这样,代码更好维护。

b.方便测试。如果将数据访问写在servlet里面,需要部署整个应用才能测试。

<4>.JSP概念,java代码片段,html转jsp…

1.jsp

(1)jsp是什么?

sun公司制订的一种服务器端动态页面技术规范。

注:
	虽然使用Servlet也可以生成动态页面,但是过于繁琐(需要使用out.println语句),并且不利于页面的维护(比如,要修改页面就必须修改java代码),所以,sun才制订了jsp技术规范。
	jsp其实是一个以.jsp为后缀的文件,主要内容是html和少量的java代码。容器会将jsp文件转换成一个对应的servlet然后执行。
	记住,jsp的本质就是一个servlet!

(2)如何写一个jsp文件?

step1. 添加一个以.jsp为后缀的文件。

step2. 在该文件里面,可以使用如下元素:

1)html(css,javascript)
直接写即可。
2)java代码
方式一 java代码片断
<% java代码  %>
方式二  jsp表达式
<%= java表达式 %>
3)隐含对象
a.什么是隐含对象?
	直接可以使用的对象,比如out、request、response。
b.为什么可以直接使用这些隐含对象?
	因为容器会自动添加获得这些对象的语句。
4)指令
a.什么是指令?
通知容器,在将jsp文件转换成一个Servlet类时,
做一些的额外的处理,比如导包。
b.指令的语法
<%@ 指令名 属性=值 %>
c.page指令
	import属性:用于指定要导的包名。
	比如 
<%@ page import="java.util.*,java.text.*"%>
	contentType属性:设置response.setContentType方法的内容。
	pageEncoding属性:告诉容器,在读取jsp文件的内容时,使用指定的字符集来解码。

在这里插入图片描述

(3)jsp是如何执行的?

1)阶段一 容器将.jsp文件转换成一个Servlet类。
html(css,js) ----> service方法里面,使用out.write输出。
<%       %>  -----> service方法里面,照搬。
<%=      %>  -----> service方法里面,使用out.print输出。
2)阶段二 容器调用该Servlet
需要编译、实例化、然后调用service方法。
练习 写一个date.jsp,输出当前的系统日期,比如
输出 "2018-10-31"	

<5>.转发,相对路径与绝对路径

1.转发

(1)什么是转发?

一个web组件将未完成的处理交给另外一个web组件继续做。

注:
	web组件: jsp或者servlet的统称。
	通常是一个servlet获得数据,然后转发给一个jsp来展现。

在这里插入图片描述

(2)如何转发?

step1.绑订数据到request对象上。

request.setAttribute(String name,Object obj);
注:
	a. name通常称之为绑订名,obj称之为绑订值。
	b. 该方法内部的实现:就是以name作为key,以
		obj作为value,调用Map.put方法。
	c.  Object request.getAttribute(String 	name);

step2.获得转发器。

RequestDispatcher rd = 
		request.getRequestDispatcher(Sting uri);
注:
	a.uri:转发的目的地,通常是一个jsp。
	b.RequestDispatcher是一个接口,该方法会返回	一个符合该接口的对象,这个对象一般我们称之为转发器。	
	c.转发的本质是一个web组件通知容器去调用另外一个web组件,可以将转发器理解为web组件通知容器的媒介。

step3.转发

	rd.forward(request,response);
(3)特点

a.转发之后,浏览器地址栏的地址不变。

b.转发的目的地有限制,要求属于同一个web应用。

2.比较转发与重定向

(1)地址栏地址有无变化

转发之后,浏览器地址栏地址不变;重定向之后,浏览器地址栏地址会发生改变。

(2)目的地有无限制

转发有限制,重定向没有任何限制。

(3)能否共享request对象和response对象。

转发可以,重定向不行。

注:
	容器收到请求之后,会立即创建request对象和response对象。当响应发送完毕,容器会立即销毁这两个对象。也就是说,request对象和response对象的生存时间是一次请求与响应期间存在。
	重定向是两次请求。
(4)一件事是否完成

转发是一件事未做完,让另外一个web组件继续做;
而重定向是一件事已经完成,再做另外一件独立的事件。

2.路径问题

链接、表单提交、重定向和转发如何填写相应的路径

<a href=""></a>
<form action="">
response.sendRedirect("")
request.getRequestDispatcher("")
(1)什么是相对路径?

不以"/"开头的路径

(2)什么是绝对路径?

以"/"开头的路径

(3)如何写绝对路径?

链接、表单提交、重定向从应用名开始写;转发从应用名之后开始写。

注:
	不要将应用名直接写在路径里面!
	应该使用以下方法来获得实际部署时的应用名:
		String request.getContextPath();
	
	在实际开发时,建议尽量使用绝对路径。
练习

添加用户时,如果用户名已经存在,则在添加用户的页面上
提示“用户名已经存在”。否则,将用户信息插入到数据库,然后重定向到用户列表。

提示:

step1.在UserDAO类中添加一个方法

public User findByUsername(String uname);
public User findByUsername(String name) throws Exception {
		//假设找不到
		User user = null;
		Connection conn = null;
		PreparedStatement ps = null;
		ResultSet rs = null;
		try {
			conn = DBUtils.getconnn();
			String sql ="select * from t_user where username=?";
			ps=conn.prepareStatement(sql);
			ps.setString(1,name);
			rs = ps.executeQuery();
			
			if(rs.next()) {
				user = new User();
				user.setId(rs.getInt(1));
				user.setUsername(rs.getString(2));
				user.setPwd(rs.getString(3));
				user.setEmail(rs.getString(4));
			}
		} catch (Exception e) {
			e.printStackTrace();
			throw e;
		}finally {
			DBUtils.close(rs, ps, conn);
		}
		return user;
	}

step2.修改AddUserServlet

调用UserDAO的findByUsername方法,如果返回值不为null,则绑订错误提示信息到request,然后转发到addUser.jsp;否则调用UserDAO的save方法,将用户信息插入到数据库。
public class AddUserServlet extends HttpServlet{

	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		/**
		 * 用来处理表单中文参数值的问题  这里的字符集要和表单页面的字符集得一致
		 */
		request.setCharacterEncoding("utf-8");  //提交的表单里有中文,就这么处理       
		
		//输出用户信息
		/**
	     * 这行代码的作用:
		 * 1.设置content-type消息头的值
		 * 2.out.println方法在输出时,会使用charset指定的字符集来编码。
		 */
		response.setContentType("text/html;charset=utf-8");
		PrintWriter out = response.getWriter(); 				//获得输出流   
		
		//读取用户信息
		String username = request.getParameter("username");
		
		UserDao userdao = new UserDao();
		try {
			/**
			 * 先查看用户名是否存在,如果已经存在,则转发到addUser.jsp,提示用户名已经存在;否则,将该用户的信息插入到数据库,重定向到
			 * 用户列表。
			 */
			User user = userdao.findByUsername(username);
			if(user!=null){
				 request.setAttribute("msg","该用户名已被占用");//step1.将数据绑定到request对象上。
				 RequestDispatcher rd = request.getRequestDispatcher("addUser.jsp");//step2.获得转发器
				 rd.forward(request, response);//step3.转发
			}else {
				//注意: 为空不能调用..方法所以要。。
				user=new User();   //避免空指针异常
				user.setUsername(request.getParameter("username"));
				user.setPwd(request.getParameter("password"));
				user.setEmail(request.getParameter("email"));
				userdao.addUser(user);
				response.sendRedirect("list");               ///给浏览器发送302状态码,让浏览器马上访问消息头Location: list
			}
		} catch (Exception e1) {
			e1.printStackTrace();
			out.println("系统繁忙,稍后重试");
		}
	}
	
}

step3.修改addUser.jsp (显示提示信息)

在这里插入图片描述
上面的"msg"是servlet中绑定的数据的key值。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值