java servlet jsp (服务器端编程)


	注:自动添加protected void service(HttpServletRequest request,HttpServletResponse response)throws ServletException, IOException {              的方法步骤     
	   右键空白处-source-Override/Implement Methods...-getLastModifed(....)

如果复制粘贴servlet项目,别先部署,需要右键项目名-Properties-web Project Settings-Context root: 名称更改为和现名称一样。。
  如果先部署了 会导致服务器运行报错, 这种情况需删除粘贴的项目 部署复制项目后在重新粘贴。


# 1.什么是Servlet?  
sun公司制订的一种用来扩展web服务器功能的组件规范。

![](s1.png)

## (1)扩展web服务器功能

	web服务器只能够处理静态资源的请求(即需要事先将
	静态页面写好),不能够处理动态资源的请求(即需要进行计算,生成动态页面),所以,需要扩展其功能。
	可以使用Servlet来扩展web服务器功能,web服务器收到
	请求之后,如果需要计算,则调用Servlet来处理。

## (2)组件规范
### 1)什么是组件?
符合规范、实现部分功能,并且需要部署到相应的容器当中才能运行的软件模块。

	Servlet是一个组件,必须符合Servlet规范,并且需要部署到Servlet容器当中才能运行。

### 2)什么是容器?
符合规范、提供组件运行环境的程序。
	
	Servlet容器(比如Tomcat)为Servlet提供运行环境
	(主要是提供网络相关的服务)

# 2.如何写一个Servlet?
step1.写一个java类,实现Servlet接口或者继承HttpServlet。

step2.编译。

step3.打包。(即建立一个具有如下结构的文件夹)

	appname
		WEB-INF(自定义名字) 
			classes (.class文件)
			lib (可选,放.jar文件)
			web.xml (部署描述文件)

step4.部署。

	把step3创建好的文件夹拷贝到容器指定的位置。
	注:
		可以将step3创建好的文件夹压缩成".war"为后缀
		的文件,然后拷贝。

step5.启动容器,访问Servlet。

	http://ip:port/appname/url-pattern
	注:
		url-pattern在web.xml中设置。

# 3.Servlet是如何运行的?
比如,在浏览器地址栏输入http://localhost:8080/day01/hello

![](s2.png)

	step1.浏览器依据ip和port建立连接。
	step2.浏览器将相关数据放到请求数据包,然后将请求
	数据包发送给服务器。
	step3.服务器解析请求数据包,将解析到的结果放到
	request对象里面,同时,创建一个response对象。
	step4.服务器依据请求路径,创建Servlet对象,然后
	调用该对象的service方法。
		注:
			开发人员只需要调用request对象的方法,就
		可以获得请求数据包中的数据。类似的,只需要调用
		response对象的方法,就可以将处理结果写到
		response对象里面,容器会从response对象中取
		出处理结果,然后创建响应数据包并发送给浏览器。
	step5.容器从response对象中取出处理结果,然后创建
	响应数据包并发送给浏览器。
	step6.浏览器解析响应数据包,生成结果页面。

# 4.常见错误
## (1)404
	a.含义:服务器依据请求路径,找不到对应的资源。
	b.错误原因:
		b1.请求路径写错。
		b2.应用没有部署或者部署失败。

## (2)500
	a.含义:服务器端程序运行发生问题。
	b.错误原因:
		b1.没有严格按照规范来写代码。
		比如,没有继承HttpServlet或者实现Servlet
		接口。又或者部署描述文件写错。

		b2.代码写得不严谨。
		比如,对请求参数值没有做任何检查就直接做类型
		转换。

## (3)405
	a.含义:服务器找不到处理方法。
	b.错误原因:
		没有正确override HttpServlet的service方法。


# 练习:
写一个Servlet(比如DateServlet),输出当前的
系统日期,比如"2018-10-25"

## 提示
## step1.创建一个maven工程。注意三个细节:

细节1:选war包,如下图所示:

![](a1.png)

细节2:工程建完之后,默认没有带web.xml文件,需要
添加web.xml文件,如下图所示:

![](a2.png)

细节3:指定servlet容器,如下图所示:

![](a3.png)

## step2.添加一个java类(DateServlet)
参考代码如下:

	public class DateServlet extends HttpServlet{
	
	public void service(
			HttpServletRequest request,
			HttpServletResponse response)
	throws ServletException,IOException{
		
		//生成日期信息
		Date date = new Date();
		SimpleDateFormat sdf = 
				new SimpleDateFormat("yyyy-MM-dd");
		String dateInfo = 
				sdf.format(date);
		//输出日期
		response.setContentType("text/html");
		PrintWriter out = 
				response.getWriter();
		out.println(dateInfo);
		out.close();
		}
	}

## step3. 在web.xml添加该Servlet的配置
参考配置如下:

	<servlet>
		<servlet-name>dateServlet</servlet-name>
		<servlet-class>web.DateServlet</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>dateServlet</servlet-name>
		<url-pattern>/date</url-pattern>
	</servlet-mapping>

## step4.部署、运行

![](a4.png)


## Tomcat的配置请参考doc.tedu.cn上的文档。

![](a5.png)	


# 课后练习
写一个Servlet,计算一个人的BMI指数。

	BMI指数 = 体重(公斤) / 身高() / 身高()


—————————————————————————————————

# 1.http协议 (了解)
## (1)什么是http协议?
是一种网络应用层协议、规定了浏览器与web服务器之间如何
通信以及相应的数据包的格式。

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

	这样做的好处是,服务器可以利用有限的连接数为尽可能
	多的请求服务。
	
![](http.png)

### 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的配置文件(Servers-Tomcat...-server.xml) 
	<Connector URIEncoding="utf-8"/>
	注:只针对get请求有效
	
#5.访问数据库
step1.导包
	jdbc驱动,连接池
	<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>

stp2.添加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);
			}
		}
	}

	注:自动添加protected void service(HttpServletRequest request,HttpServletResponse response)throws ServletException, IOException {              的方法步骤      
	  右键空白处-source-Override/Implement Methods...-getLastModifed(....)

—————————————————————————————————

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

![](redirect.png)

## (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里面,需要部署
整个应用才能测试。
	
—————————————————————————————————

# 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.*"%>

## (3)jsp是如何执行的?
### 1)阶段一 容器将.jsp文件转换成一个Servlet类。
	
	html(css,js) ----> service方法里面,使用out.write输出。
	<%       %>  -----> service方法里面,照搬。
	<%=      %>  -----> service方法里面,使用out.print输出。

### 2)阶段二 容器调用该Servlet

	需要编译、实例化、然后调用service方法。


# 练习 写一个date.jsp,输出当前的系统日期,比如
	<%@ page import="java.util.*,java.text.*" %>

<html>
	<head></head>
		<body style="font-size:30px;">
			<% 
				Date date = new Date();
				SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
			%>
			<%=sdf.format(date) %>
		</body>
</html>
	输出 "2018-10-31"	
—————————————————————————————————
编写程序,找出101200自然数中的质数,for循环越少越好(2)
(质数:一个大于1的自然数,除了1和它本身,不能被其他数整除的数字);

# 1.转发
## (1)什么是转发?
一个web组件将未完成的处理交给另外一个web组件继续做。

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

![](forward.png)

## (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);

step2.修改AddUserServlet 

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

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


—————————————————————————————————
# 1. 状态管理
## (1)什么是状态管理?
将浏览器与web服务器之间多次交互当做一个整体来处理,
并且将多次交互所产生的数据(即状态)保存下来。

## (2)如何进行状态管理?
a.方式一  将状态保存在浏览器端

	通常使用Cookie技术。

b.方式二  将状态保存在服务器端

	通常使用Session技术。

## (3)Cookie
### 1)什么是Cookie?
服务器临时存放在浏览器端的少量数据,
用于跟踪用户的状态。

	当浏览器访问服务器时,服务器会将少量数据以
	set-cookie消息头的方式发送给浏览器,浏览器
	会将这些数据保存下来。
	当浏览器再次访问服务器时,会将这些数据以cookie
	消息头的方式发送给服务器。

![](cookie.png)

### 2)如何添加Cookie?
	
	Cookie c = new Cookie(String name,String value);:
		name一般称之为cookie名,value称之为cookie值,都必须是字符串。
	response.addCookie(c);

### 3)如何读取Cookie?
	
	Cookie[] request.getCookies();
	注:
		该方法有可能返回null。
	String cookie.getName();
	String cookie.getValue();

### 4)cookie的生存时间
a.默认情况下,浏览器会将cookie保存在内存里面,浏览器
只要关闭,cookie会被删除。

b.可以调用setMaxAge方法来设置cookie的生存时间

	cookie.setMaxAge(int seconds);:
		a.单位是秒。
		b.当seconds > 0,浏览器会将cookie保存在硬盘上,当超过指定的时间,浏览器会将cookie删除。
		c.当seconds < 0,缺省值(浏览器会将cookie保存在内存里面)。
		d.当seconds = 0,删除cookie。
			比如,要删除一个名称为"username"的cookie,代码如下:
				Cookie c = new Cookie("username","");
				c.setMaxAge(0);
				response.addCookie(c);

### 5)cookie的编码问题
a.什么是cookie的编码问题?

	cookie只能存放合法的ascii字符,如果要存放中文,
	需要将中文转换成合法的ascii字符的形式。

b.如何处理?

	String URLEncoder.encode(String str,String charset);
	String URLDecoder.decode(String str,String
	charset);

	建议,在实际开发时,对添加的数据统一使用encode
	方法来编码。

### 6)cookie的路径问题
a.什么是cookie的路径问题?

	浏览器访问服务器时,会比较请求地址是否与cookie
	的路径匹配,只有匹配的cookie才会被发送。

b.cookie的默认路径

	cookie的默认路径等于添加该cookie的web组件的路径,比如AddCookieServlet(/day06/addCookie) 添加了一个cookie,则该cookie的默认路径是
	"/day06"。

c.匹配规则

	请求地址要么是等于cookie的路径,要么是cookie的
	子路径,只有符合该条件的cookie,浏览器才会发送出去。

![](path.png)

d.修改路径

	cookie.setPath(String path);:
		path就是路径。

### 7)cookie的限制
a. cookie可以被用户禁止。
b. cookie不安全。
	
	对于敏感数据,一定要加密。

c. cookie只能保存少量的数据。

	大约4k左右

d. cookie的数量也有限制。

	大约是几百个

e. cookie只能保存字符串。


# 练习
 
写一个Servlet,该Servlet先查看有没有一个名称为
"cart"的cookie,如果有,则显示该Cookie的值;如果
没有,则添加之。



# 练习
写一个Servlet,该Servlet先查看有没有一个名称为"Cart"的cookie,如果有,则显示该cookie的值,如果没有则添加。
	new Cookie("cart","123");

—————————————————————————————————

# 1.Session(会话)
## (1)session是什么?
服务器端为了保存状态而创建的一个特殊的对象。
	
	注:
		当浏览器访问服务器时,服务器端创建一个特殊的
	对象(该对象一般称之为session对象,该对象有一个
	唯一的id,一般称之为sessionId)。服务器会将sessionId以cookie的方式发送给浏览器。
		当浏览器再次访问服务器时,会将sessionId发送
	过来,服务器端可以依据sessionId找到对应的session
	对象。

## (2)如何获得session对象?
### 1)方式一:
	
	HttpSession s = 
		request.getSession(boolean flag);:
		a.HttpSession是一个接口。
		b.如果flag为true:
			先查看请求当中是否有sessionId,如果没有,
		则创建一个session对象;如果有sessionId,
		则依据sessionId查找对应的session对象,如果找
		到了,则返回该对象,找不到,则创建一个新的
		session对象。
		c.如果flag为false:
			先查看请求当中是否有sessionId,如果没有,
		返回null;如果有sessionId,则依据sessionId查找对应的session对象,如果找到了,则返回该对象,找不到,返回null。

![](session.png)

### 方式二:

	HttpSession s = request.getSession();
	等价于 request.getSession(true);

## (3)常用方法
1)session.setAttribute(String name,Object obj);:
		以name作为key,以obj作为value,将数据存放到了
		一个Map对象里面。

2)Object session.getAttribute(String name);:
		如果绑订值不存在,返回null。

3)session.removeAttribute(String name);

	注:
		解除绑订。

![](count.png)


## (4)session超时
a.什么是session超时?
	
	服务器会将空闲时间过长的session对象删除掉。
	注:
		缺省的超时时间长度一般是30分钟。

b.如何修改超时时间长度?

	方式一 修改web.xml配置文件。

	<session-config>
        <session-timeout>30</session-timeout>
    </session-config>

	方式二  
	session.setMaxInactiveInterval(int seconds)
	注:
		设置两次请求之间的最大间隔时间,如果超过了
		该时间,则session对象会被删除。

## (5)删除session
	invalidate();
如:
session.invalidate()  

	
## 2. 登录
## 3. session验证
step1.登录成功之后,在session对象上绑订一些数据,
比如:

	session.setAttribute("user",user);

step2.当用户访问需要受保护的资源时(即只有登录成功之后才能访问的资源,比如success.jsp),进行session验证,比如:

	Object obj = session.getAttribute("user");
	if(obj == null){
		//没有登录,重定向到登录页面
		response.sendRedirect("login.jsp");
		return;
	}
	
![](session_check.png)

# 练习
	显示用户上一次访问的时间,如果是第一次访问,则输出“你是第一次访问”。

—————————————————————————————————
# 1.比较session与cookie
session相对于cookie、优点是更安全、可以保存更
多的数据、支持更丰富的数据类型。缺点是需要占用服务器
端的内存空间。


# 2.Servlet的生命周期
## (1)什么是servlet的生命周期?
servlet容器如何创建servlet对象、如何对该对象进行初
始化处理、如何调用该对象处理请求,以及如何销毁该对象的
整个过程。

![](life.png)

## (2)分成哪几个阶段?

### 1)实例化
a.什么是实例化?

	容器调用servlet构造器,创建servlet对象。

b.什么时候实例化?

	情形1: 容器收到请求之后,才会创建。
	情形2: 容器启动之后,立即创建。
		注: 需要在web.xml文件当中,使用
			load-on-startup来配置。
![](s1.png)
	
c.容器只会创建一个实例!

### 2)初始化
a.什么是初始化?

	容器在创建好servlet对象之后,会立即调用该对象的
	init(ServletConfig config)方法。
	注:
		init方法只会调用一次!

b.GenericServlet已经提供了init方法的实现:

	将容器传递过来的ServletConfig对象保存下来,并
	且提供了一个方法(getServletConfig)来获得该对象。

![](s2.png)	

c.如何实现自已的初始化处理逻辑?

	只需要override GenericServlet的init()方法。

![](s3.png)	

d.初始化参数
![](a1.png)	
![](a2.png)		

### 3)就绪(调用)
a.什么是就绪?
	
	容器收到请求之后,调用servlet对象的service
	方法来处理。

b.HttpServlet已经提供了service方法的实现:
	
	依据请求类型调用对应的doXXX方法。
	注:
		比如,get请求会调用doGet方法,
		post请求会调用doPost方法。

c.开发人员可以override HttpServlet的service方法,
也可以override doXXX方法。		

![](service.png)	


### 4)销毁
a.什么是销毁?

	容器在删除servlet对象之前,会调用该对象的
	destroy方法。
	该方法只会执行一次!

b. GenericServlet已经提供了destroy方法的实现:

	什么都没有做。
	开发人员可以override GenericServlet的destroy
	方法来实现自已的销毁处理逻辑。

## (3)相关的接口与类
a. Servlet接口

	init(ServletConfig config)
	service(ServletRequest req,ServletResponse res)
	destroy()

b. GenericServlet抽象类

	实现了Servlet接口(主要是实现init、destroy方法)。

c. HttpServlet抽象类

	继承了GenericServlet,实现了service方法。


# 练习:计算一个人的BMI指数

bmi指数 = 体重(公斤) / 身高() / 身高();
如果 bmi指数 < 19,体重过轻。
如果 bmi指数 > 25,体重过重。
其它 体重正常。

	19,25要使用初始化参数来配置。
	<init-param>
		<param-name>min</param-name>
		<param-value>19</param-value>
	</init-param>

—————————————————————————————————

# 1.过滤器
## (1)什么是过滤器?
servlet规范当中定义的一种特殊的组件,用于拦截servlet
容器的调用过程。

	注:
		容器收到请求之后,会先调用过滤器,再调用
	servlet或者其它资源。

![](filter.png)

## (2)如何写一个过滤器?
step1.写一个java类,实现Filter接口。

step2.在doFilter方法里面,实现拦截处理逻辑。

step3.配置过滤器。(web.xml)

## (3)过滤器的优先级
当有多个过滤器满足拦截的要求,则容器依据
<filter-mapping>配置的先后顺序来执行。

## (4)初始化参数
step1.配置初始化参数

	<init-param>
  		<param-name>size</param-name>
  		<param-value>5</param-value>
  	</init-param>

step2.调用FilterConfig提供的getInitParameter
方法来读取初始化参数

	//读取初始化参数
	int size = Integer.parseInt(
		config.getInitParameter("size"));

## (5)过滤器的优点(思考)

# 练习 
写一个过滤器,检查评论的字数,如果超过
10个字,提示“评论字数过多”。


# 2.容器如何处理请求资源路径
比如,在浏览器地址栏输入http://ip:port/day09-2/abc.html,浏览器会将"/day09-2/abc.html"作为请求资源
路径发送给服务器(容器)。

step1.默认认为访问的是一个servlet,容器会去查找对应的
servlet。

	注:
		看web.xml文件中<url-pattern>的配置,有没有
	对应的servlet。

	<url-pattern>有三种配置方式:
	第一种:精确匹配
		比如 	
		<url-pattern>/abc.html</url-pattern>
	第二种:通配符匹配
		使用 "*"号匹配任意的零个或者多个字符,比如
		<url-pattern>/*</url-pattern>
		<url-pattern>/demo/*</url-pattern>
	第三种:后缀匹配
		使用"*."开头,后接一个后缀,比如
		<url-pattern>*.do</url-pattern>
		会匹配所有以.do结尾的请求。
		
step2 如果没有找到对应的servlet,容器会查找对应位置的文件。

# 3.如何让一个servlet处理多种请求?
step1.采用后缀匹配,比如

	<servlet-mapping>
    	<servlet-name>SomeServlet</servlet-name>
    	<url-pattern>*.do</url-pattern>
  	</servlet-mapping>

step2.分析请求资源路径,进行相应的处理。

		//先获得请求资源路径
		String uri = request.getRequestURI();
		System.out.println("uri:"  + uri);
		//为了方便比较,截取请求资源路径的一部分
		String path = 
			uri.substring(uri.lastIndexOf("/"),
					uri.lastIndexOf("."));
		System.out.println("path:" + path);
		if("/login".equals(path)) {
			System.out.println("处理登录请求...");
		}else if("/list".equals(path)) {
			System.out.println(
					"处理用户列表请求...");
		}

—————————————————————————————————

## (5)过滤器的优点
a.可以在不修改源代码的基础上,为应用添加新的功能。
b.可以将多个组件相同的功能集中写在过滤器里面,方便
代码的维护。

# 1.监听器
## (1)什么是监听器?
servlet规范当中定义的一种特殊的组件,用于监听servlet
容器产生的事件并进行相应的处理。

	注:
		主要有两大类事件:
		a.生命周期相关的事件:
			 当容器创建了或者销毁了request,session,
			 servlet上下文时产生的事件。
		b.绑订数据相关的事件:
			 调用了request,session,servlet上下文的
			 setAttribute和removeAttribute方法时产
			 生的事件。

## (2)servlet上下文
### 1)什么是servlet上下文?
容器在启动之后,会为每一个web应用创建唯一的一个符合
ServletContext接口要求的对象,该对象会一直存在,除非
应用被卸载或者容器关闭。

	注:
		该对象有两个特点:
		a.唯一性:一个web应用对应一个上下文。
		b.持久性:上下文会一直存在,除非应用被卸载或者容器关闭。

### 2)如何获得servlet上下文
GenericServlet,ServletConfig,FilterConfig,
HttpSession都提供了一个方法(getServletContext)来
获得该对象。

### 3)作用1 绑订数据
	注:
		request,session,servlet上下文都提供了
		绑订数据相关的方法,区别如下:
		a.绑订的数据,生存的时间不一样:
		request < session < servlet上下文。
		在满足使用条件的情况下,优先使用生命周期短的。

![](sctx.png)

		b.绑订的数据,可访问的范围不一样:
		绑订到session对象上的数据,只有与之对应的用户
		能够访问到;绑订到servlet上下文上的数据,所有
		用户都可以访问。

![](s1.png)

### 4)作用2:读取全局的初始化参数
step1.配置全局的初始化参数

	<!-- 配置全局的初始化参数 -->
  	<context-param>
  		<param-name>company</param-name>
  		<param-value>IBM</param-value>
  	</context-param>

step2.调用servlet上下文的方法来读取

	String company = 
			sctx.getInitParameter("company");

## (3)如何写一个监听器?
step1.写一个java类,依据监听的事件类型选择实现相应的
监听器接口。
	
	注:
		比如,要监听session对象的创建和销毁,需要
		实现HttpSessionListener接口。

step2.在接口方法当中,实现监听处理逻辑。

	
step3.配置监听器。(web.xml)


# 统计在线人数	
![](count.png)	


# 练习
![](lab.png)


# 2.servlet的线程安全问题
## (1)为什么说servlet会有线程安全问题?
a.容器只会创建一个servlet实例。

b.容器收到一个请求,就会启动一个线程,由该线程来处理
对应的请求。
如果有多个线程同时去调用某个servlet实例的方法,就有可能产生线程安全问题,比如,这些线程要修改servlet的某个
属性值。

![](s2.png)

## (2)如何解决?
使用synchronized对有可能产生线程安全问题的代码加锁。

	注:
		加锁会影响性能。


# 3.servlet小结
## (1)servlet基础
	1)什么是servlet?
	2)如何写一个servlet?
	3)servlet是如何运行的?
	4)http协议(了解)	
## (2)servlet核心
	1)如何读取请求参数值?
	2)表单包含有中文参数值,如何处理?
	3)servlet输出中文,如何处理?
	4)容器如何处理请求资源路径?
	5)如何让一个servlet处理多种请求?
	6)转发与重定向
		a.什么是重定向?
		b.如何重定向?
		c.重定向的特点?
		d.什么是转发?
		e.如何转发?
		f.转发的特点?
		g.比较转发与重定向
	7)线程安全问题
	8)servlet的生命周期
		a.什么是servlet的生命周期?
		b.生命周期分成哪几个阶段?
		c.容器会创建几个servlet实例?
		d.load-on-startup
		e.如何实现自已的初始化处理逻辑?
		f.初始化方法会执行几次?
		g.doGet/doPost方法的作用?
		h.相关的接口与类(Servlet,GenericServlet,
			HttpServlet)。
		i.ServletConfig。
		j.初始化参数的配置。
	9)路径问题
	10)servlet上下文
		a.什么是servlet上下文?
		b.有什么特点?
		c.如何获得servlet上下文?
		d.作用
	11)将异常抛给容器来处理	
## (3)状态管理
	1)什么是状态管理?
	2)如何进行状态管理?
	3)Cookie
		a.什么是cookie?
		b.如何添加cookie?
		c.添加cookie时需要考虑的三个问题:
			生存时间
			编码问题
			路径问题
		d.如何读取cookie?
		e.cookie有哪些限制?
	4)Session
		a.什么是session?
		b.如何获得session对象?
		c.session常用的方法
		d.session超时
		e.如何删除session?	
		f.比较session与cookie?
## (4)数据库访问
	1)什么是dao?
	2)如何写一个dao?
## (5)过滤器与监听器
## (6)典型案例
	用户管理
	登录(session验证)
		
—————————————————————————————————
# 1.jsp基础
## (1)什么是jsp?
sun公司制订的一种服务器端的动态页面技术规范。

	注:
		虽然使用servlet也可以生成动态页面,但是
	过于繁琐(需要使用out.print语句),并且不利于页
	面的维护(如果修改页面,就需要修改java代码),所以,
	sun才推出了jsp规范。

		jsp是一个以.jsp为后缀的文件,主要内容是
	html和少量的java代码。容器会将jsp转换成一个
	servlet然后执行。

## (2)如何写一个jsp文件?
### 1)step1.写一个以.jsp为后缀的文件

### 2)step2.可以添加如下内容:
a.html(css,js): 直接写。

b.java代码:
	
	第一种:java代码片断
			<%  java代码  %>
	第二种: jsp表达式
			<%= java表达式 %>
	第三种: jsp声明   (a1.jsp)
			<%! 声明一个变量或者方法 %>
c.隐含对象:

	什么隐含对象?
		直接可以使用的对象。
	为什么可以使用这些隐含对象?
		容器会自动添加获得这些对象的代码。
	有哪些隐含对象?
		out,request,response
		session   
		application
		pageContext: 容器会为每一个jsp实例创建唯一的
				一个符合PageContext接口要求的对象,
				该对象会一直存在,除非jsp实例被删除。
				作用1:绑订数据。(a2.jsp,a3.jsp)
					注:绑订到pageContext上的数据,
					只有对应的jsp实例能够访问,类似于“钱包”。
![](pagecontext.png)

				作用2:提供了一些方法,用于获得其它
					所有隐含对象。
		
		config: ServletConfig (a4.jsp)
		exception: 获得异常的描述性信息。(a5.jsp,a6.jsp)
				注:只有当page指令的isErrorPage
					属性值为true时,才能使用。
									
		page (了解)  jsp实例本身。
				注:jsp实例是jsp对应的servlet对象。 

d.指令
	
	什么是指令?
		告诉容器将jsp转换成一个servlet时,做一些额外的处理,比如导包。
	指令的语法:
		<%@ 指令名 属性=值  %>
	page指令
		import属性:导包。
		pageEncoding属性:设置jsp页面的编码。
		contentType属性:设置	response.setContentType的内容。
		errorPage属性:指定一个异常处理页面。当jsp
			运行时发生了异常,容器会调用异常处理页面。
		isErrorPage属性:缺省值是false,如果为true,	就可以使用exception隐含对象。
		session属性: (a7.jsp)缺省值是true,如果为false,则不能够使用session隐含对象了。	

	include指令
		告诉容器,在将jsp转换成servlet时,将file
		属性指定的文件的内容插入到该指令所在的位置。
		file属性:指定被包含的文件名。
		注:
			被包含的jsp并没有真正执行,只是负责提供
			内容。所以,被包含的文件也可以是其它类型
			的文件,比如html文件。

	taglib指令
			导入jsp标签。

e.注释  (a8.jsp)
	
	<!-- 注释的内容 -->
			注: 如果被注释的内容是java代码,java
				代码会执行,但是执行结果并不会在浏览
				器端显示出来。
	<%-- 注释的内容 --%>
			注:如果被注释的内容是java代码,不会执行。
				

## (3)jsp是如何执行的?
### step1. 容器要将jsp转换成一个servlet。

	html(css,js) ----> 在service方法里面,使用
					out.write输出。
	<%    %> ---->  在service方法里面,照搬。
	<%=   %> ---->  在service方法里面,使用					out.print输出。
	<%!   %> ---->  添加新的属性或者方法。


# 2.jsp标签和el表达式
## (1)什么是jsp标签?
是sun公司为了替换jsp中的java代码而推出的一种技术,
语法类似于html标签(有开始标记、属性、结束标签、标签体)。

	注:
		因为在jsp当中写java代码,不利于jsp文件的
		维护,比如美工去修改带有java代码的jsp文件就
		很不方便,所以sun才推出了jsp标签技术规范。
		使用jsp标签,美工修改就很方便,另外,jsp
		页面变得简洁,方便代码的复用。
		
## (2)什么是el表达式?
是一套简单的运算规则,用于给jsp标签的属性赋值。

	注: el表达式也可以脱离jsp标签直接使用。

## (3)el表达式的使用
### 1)读取bean的属性
	注(了解):
		如果一个类,满足如下几个条件,我们就可以称之为是一个javabean。
		public class
		public 构造器
		最好实现Serializable接口
		有一些属性及对应的get/set方法

#### 方式一 ${user.username}  e1.jsp
	注:
		a.执行过程: 
			容器依次从pageContext-->request-->
			session-->application中查找绑订名为
			"user"的对象(即调用getAttribute方法),
			接下来,调用该对象的"getUsername"方法,
			然后输出。
		b.优点:
			el表达式比java代码更简洁。
			会将null转换成""输出。
			如果依据绑订名找不到对应的对象,
			不会发生空指针异常。
		c.可以使用pageScope,requestScope,sessionScope,
		applicationScope来指定查找范围

#### 方式二 ${user['username']}
	注:
		a. []里面还可以使用绑订名。
		b. []里面还可以使用从零开始的下标,用于
			读取数组中指定下标的某个元素的值。

### 2)使用el表达式做一些简单的运算 (e2.jsp)
#### a.算术运算

	+,-,*,/,%
	注:
		+ 只能求和。
	
#### b.关系运算

	>,<,==,!=,>=,<=
	
#### c.逻辑运算

	&&, ||,!

#### d.empty运算
	
	判断集合是否为空或者是否为一个空字符串,如果是,
	返回true。

### 3)读取请求参数值  (e3.jsp)
a.${param.username}
	
	等价于request.getParameter("username");

b.${paramValues.interest}

	等价于request.getParameterValues("interest");


# 练习  使用el表达式输出某个员工的所有信息。
	Employee类(ename,salary,age)

—————————————————————————————————

# 1.jstl
## (1)什么是jstl?
apache开发的一套jsp标签,后来捐献给了sun,sun将其命名为jsp standard taglib,简称为jstl。

## (2)如何使用jstl?
step1.导包。(jstl)

	<dependency>
  		<groupId>jstl</groupId>
  		<artifactId>jstl</artifactId>
  		<version>1.2</version>
	</dependency>

step2.使用taglib指令导入jsp标签。

	<%@ taglib uri="" prefix=""%>
	uri属性:指定jsp标签的命名空间。
		注:
			命名空间是为了区分同名的元素在元素前添加
			的一段说明。为了防止命名空间也冲突,经常使用域名来允当命名空间。
	prefix属性:指定命名空间的别名。

## (3)if标签  (if.jsp)
### 1)语法
	<c:if test="" var="" scope="">   
		标签体		
	</c:if>
### 2)用法
	a.当test属性值为true,执行标签体的内容。
	b.test属性可以使用el表达式来计算。
	c.var属性用来指定绑订名,scope属性指定绑订范围
	(可以是 page,request,session,application),
	绑订值是test属性值。

## (4)choose标签 (choose.jsp)
### 1)语法
	<c:choose>
		<c:when test="">
			标签体
		</c:when>
		<c:otherwise>
		</c:otherwise>
	</c:choose>
### 2)用法
	a.when可以出现1次或者多次,相当于一个if语句,当
	test属性值为true时,执行标签体的内容。
	b.otherwise可以出现0次或者1次,相当于最后那个else(表示例外)。

## (5)forEach标签 (forEach.jsp)
### 1)语法
	<c:forEach items="" var="" varStatus="">
	</c:forEach>
### 2)用法
	a.用来遍历集合或者数组。
	b.items属性用来指定要遍历的集合或者数组,可以
	使用el表达式来赋值。
	c.var属性用来指定绑订名。
	注:
		绑订范围固定是pageContext。
		该标签每次从集合或者数组中取一个元素,然后将
		该元素绑订到pageContext上。
	d.varStatus属性用来指定绑订名。
	注:
		绑订范围固定是pageContext。
		绑订值是一个特殊的对象,该对象由该标签内部创建,用来获得当前遍历的状态。比如,该对象提供
		了如下几个方法:
			getIndex(): 获得当前正在被遍历的元素的下标(从0开始)。
			getCount():获得当前正在被遍历的元素的序号(从1开始)。

# 2.自定义标签
## step1.写一个java类,继承SimpleTagSupport类。

	注:
		标签技术有两种,一种是复杂标签技术(old),
		一种是简单标签技术(new)。继承SimpleTagSupport类属于简单标签技术。

## step2.override doTag方法

	注:
		在该方法里面,写处理逻辑。

## step3.在.tld文件里面描述该标签。

	注:
		该文件要添加到WEB-INF下,
	可以参考c.tld文件来写。

## 参考代码

	/**
	 * 标签类的要求:
	 * 1.继承SimpleTagSupport类。
	 * 2.override doTag方法,在该方法里写处理逻辑。
	 * 3.标签有哪些属性,标签类也得有对应的属性,
	 * 并且属性名要相同,类型要匹配,还得有对应的
	 * set方法。
	 *
	 */
	public class HelloTag 
		extends SimpleTagSupport{
		
		private String msg;
		private int qty;
		
		public HelloTag() {
			System.out.println(
					"HelloTag的构造器");
		}
		
		public void setMsg(String msg) {
			System.out.println(
					"HelloTag的setMsg方法...");
			this.msg = msg;
		}
	
		public void setQty(int qty) {
			System.out.println(
					"HelloTag的setQty方法...");
			this.qty = qty;
		}
	
		@Override
		public void doTag() throws JspException, IOException {
			System.out.println(
					"HelloTag的doTag方法...");
			/*
			 * 通过继承自SimpleTagSupport类提供的
			 * 方法来获得pageContext。
			 * pageContext提供了获得其它所有隐含对象
			 * 的方法。
			 */
			PageContext pctx = 
					(PageContext)getJspContext();
			JspWriter out = pctx.getOut();
			for(int i = 0; i < qty; i ++){
				out.println(msg + "<br/>");
			}
		}
	}

## 参考配置

	<tag>
	    <name>hello</name>
	    <tag-class>tag.HelloTag</tag-class>
	    <!--
	    	body-content用来设置标签体的内容。
	    	有三个值。
	    	empty: 该标签没有标签体。
	    	scriptless:该标签有标签体,但是,标签
	    		体里面不能够出现java代码。即不能够
	    		出现<%  %> <%= %> <%!  %>
	    	JSP:该标签有标签体,并且标签体里面可以出
	    		现java代码。但是,只有复杂标签技术才
	    		支持该值。
	     -->
	    <body-content>empty</body-content>
	    <attribute>
	        <name>msg</name>
	        <!-- 
	        	值为true,表示该属性是必须的。
	         -->
	        <required>true</required>
	        <!-- 
	        	值为true,表示该属性可以动态
	        	赋值(比如使用el表达式来赋值)
	         -->
	        <rtexprvalue>false</rtexprvalue>
	    </attribute>
	    <attribute>
	    	<name>qty</name>
	    	<required>true</required>
	    	<rtexprvalue>true</rtexprvalue>
	    </attribute>
  	</tag>



# 练习
将day09-lab工程中的listUser.jsp的java代码
使用jsp标签和el表达式来代替。

# 练习
开发一个date标签,可以按照指定的日期格式输出当前的
系统日期。

	<d:date pattern="yyyy-MM-dd"%>
	
—————————————————————————————————

# 1.MVC是什么?
是一种软件架构思想、其核心思想是,在设计一个软件的时候,应该将软件划分成模型、视图、控制器这三种不同
类型的模块。其中,模型负责数据处理(业务逻辑),视图负责数据展现(表示逻辑),控制器负责协调模型和视图。

	注:
		视图将请求发送给控制器,由控制器来选择对应的
	模型来处理;模型返回的结果也要给控制器,由控制器选择对应的视图来展现。


# 2.如何使用MVC?
在开发一个web应用时,我们可以使用servlet充当控制器,
使用jsp充当视图,使用java类充当模型。它们的关系如下图
所示:

![](mvc.png)

# 3.MVC的优点?
a.将数据处理与数据展现分开,方便代码的维护。

	注:
		比如,模型返回的数据,可以使用不同的视图
	来展现。又比如,要调用新的模型,不用修改视图。

b.方便测试。
	
	注:
		比如,将业务逻辑写在java类里面,可以直接
	测试。如果将业务逻辑写在servlet类里面,需要部署
	整个应用才能测试。

c.方便分工协作。

# 4.MVC的缺点
使用MVC,会增加代码量,增加软件设计的难度、相应会增加
软件开发的成本。所以,只有有一定规模、并且要求
具有良好的维护性与扩展性的软件,才需要使用MVC。




# 练习
	将day12-lab中所有jsp移到WEB-INF下,修改代码,
	使之正常运行。


# 5.实现一个MVC框架(SmartMVC)
## (1)目标
实现一个通用的控制器(DispatcherServlet)。

	注:
		使用SmartMVC来开发一个web应用,只需要
		开发模型和视图。

## (2)架构
### 1)主要组件
a. DispatcherServlet (控制器)

	接收请求,依据HandlerMapping的配置,调用
	处理器来处理。
	依据处理器返回的结果(视图名),调用对应的视图
	来展现处理结果。

b. HandlerMapping (映射处理器)

	负责提供请求路径与处理器的对应关系。

c. Controller (处理器)
	
	负责处理业务逻辑,返回视图名。

### 2)这几个组件的关系。

	step1.请求先发送给DispatcherServlet,DispatcherServlet收到请求之后,会依据HandlerMapping的配置,调用对应的处理器来处理。
	step2.处理器(Controller)处理请求,返回视图名给
	DispatcherServlet。
	step3.DispatcherServlet会依据视图名调用对应的视图。

![](smartmvc.png)


				
		

				









  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

҉人间无事人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值