学习目标1. Tomcat & Servlet2. cookie& session3. EL && JSTL能够说出el表达式的作用 能够使用el表达式获取javabean的属性 能够使用jstl标签库的if标签 能够使用jstl标签库的foreach标签
5. filter & listener能够说出过滤器的作用 能够编写过滤器 能够说出过滤器声明周期相关方法 能够根据过滤路径判断指定的过滤器是否起作用 能够理解什么是过滤器链 能够完成filter完成用户登录验证案例 能够理解动态代理对类的方法进行增强 能够了解listener概念
day13 Tomcat&Servlet1. web服务器软件1. 服务器安装了服务器软件的计算机 2. 服务器软件接收用户的请求,处理请求,做出响应 web服务器软件:接收用户的请求,处理请求,做出响应 3. 常见java相关的web软件4. javaEE:java语言在企业级开发中使用的技术规范的综合,一共规定了13项大的规范。 2. Tomcat1. 安装卸载相关启动可能遇到的问题: 黑窗口一闪而过: 原因:没有正确配置JAVA_HOME环境变量,或者CATALINA_HOME之类的环境变量错误 解决方案:正确配置JAVA_HOME环境变量,或者在CMD命令行启动,会报相应的错 或者编辑 startup.bat,在末尾加一个pause
启动报错
2. 配置 部署项目的方式直接将项目放到webapps目录下(使用的较多,方便,针对小项目) 配置conf/server.xml文件(强烈不建议使用) 在<Host>标签体中配置 <Context docBase="D:/hello" path="/hehe" /> docBase 项目存放的位置,path虚拟目录 热部署在conf/Catalina\localhost创建任意名称的xml文件,在文件中编写 <Context docBase="D:\hello"> 3. 静态项目和动态项目1. java动态项目的目录结构-- 项目的根目录
-- WEB-INF目录
-- web.xml:web项目的核心配置文件
-- classes目录: 放置字节码文件的目录
-- lib目录: 放置依赖的jar包
2. Tomcat 集成到idea集成到idea,常见javaEE的项目,部署项目 热部署,如何集成到idea 3. Servlet1. 概念:运行在服务器端的小程序 servlet就是一个接口,定义了java类被浏览器访问到(tomcat识别)的规则 一个Java类,要想被浏览器访问到(Tomcat识别到),必须实现servlet接口 我们自己定义一个类,实现Servlet接口,复写方法 2. 快速入门3. 执行原理当服务器接收到客户端浏览器的请求后,会解析请求url路径,获取访问的servlet的资源路径 查找web.xml文件,是否有对应的<url-pattern>标签体内容 如果有,则再找对应的<servlet-class>全类名 Tomcat会将字节码文件加载进内存Class.forName("全类名"),并且创建其对象cls.newInstance() 调用service方法
4. servlet的生命周期1. 被创建执行init方法,只执行一次 servlet什么时候被创建? 默认情况,第一次被访问时,创建 可以配置指定servlet的创建时机
指定servlet的创建时机 servlet的init方法,只执行一次,说明一个servlet在内存中只存在一个对象,servlet是单例的 2. 提供服务执行service方法,执行多次 3. 被销毁执行destroy方法,只执行一次 只有服务器正常关闭时,才会执行,一般用于释放资源 5. servlet3.0好处:支持注解配置,可以不需要web.xml 步骤: 6. IDEA与Tomcat的相关配置7. servlet相关配置urlpattern: servlet访问路径 一个servlet可以定义多个访问路径:@WebServlet({"/d4","/dd4","/ddd4"}) 路径定义规则: 优先级: 绝对匹配 /xxx > /* > *.do
file://C:/Users/Lenovo/Desktop/java%E5%9F%BA%E7%A1%80%E5%BF%85%E8%83%8C%E7%9F%A5%E8%AF%86%E7%82%B9/img/url_pattern.png?lastModify=1553751539 servlet的体系结构genericServlet类:将servlet接口中其他方法做了默认空实现,只将service()方法作为抽象 将来定义servlet类时,可以继承GenericServlet,实现service()方法即可 HttpServlet: 对http协议的封装,简化操作 Ctrl+H 查看继承
GenericServlet类:
public void init(ServletConfig config) throws ServletException {
this.config = config;
this.init();//调用init()方法,将init()方法里的方法体内容输出
}
public void init() throws ServletException {
}
Servlet接口:
public interface Servlet {
void init(ServletConfig var1) throws ServletException;
ServletConfig getServletConfig();
void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
String getServletInfo();
void destroy();
}
public abstract class HttpServlet extends GenericServlet
为什么GenericServlet重写了Servlet的init方法后,自己又写了个空参的init()方法day14-18 HTTP1. 概念Hyper Text Transfer Protocol超文本传输协议 传输协议:定义了客户端和服务器端通信时,发送数据的格式 特点: 基于TCP/IP的高级协议 默认端口:80 基于请求/响应模型的:一次请求对应一次响应 无状态的:每次请求之间相互独立,不能交互数据
历史版本 1.0:每一次请求都会响应都会建立新的连接 1.1:复用连接
发展史: 在java开发中不管用线程,数据库,网路请求,建立的连接,都是宝贵的,不要随意乱用和浪费 2. request1. request消息数据格式file://C:/Users/Lenovo/Desktop/java%E5%9F%BA%E7%A1%80%E5%BF%85%E8%83%8C%E7%9F%A5%E8%AF%86%E7%82%B9/img/%E5%9B%BE%E4%B8%80%20HTTP%E5%8D%8F%E8%AE%AE%E7%9A%84%E8%AF%B7%E6%B1%82%E9%83%A8%E5%88%86.bmp?lastModify=1553751539 1. 请求行请求方式 请求url 请求协议/版本 GET /login.html HTTP/1.1 2. 请求头客户端浏览器告诉服务器一些信息 请求头名称:请求头值 常见的请求头: 3. 请求空行空行,分隔post请求头和请求体 4. 请求体(正文)封装POST请求消息的请求参数的 字符串格式
POST /login.html HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Referer: http://localhost/login.html
Connection: keep-alive
Upgrade-Insecure-Requests: 12. request对象1. request对象和response对象的原理Tomcat服务器会根据请求url中的资源路径,创建对应的servletDemo1的对象 Tomcat服务器,会创建request和response对象,request对象中封装请求消息数据 Tomcat将request和response对象传递给service方法,并且调用service方法 程序员,可以通过request对象获取请求消息数据,通过response对象设置响应消息数据 服务器再给浏览器做出响应之前,会从response对象中拿程序员设置的响应消息数据
2. request对象的继承体系结构
ServletRequest --接口
|
HttpServletRequest -- 接口
|
org.apache.catalina.connector.RequestFacade类实现
3. request功能1. 获取请求行消息数据获取请求行数据 GET /day14/demo1?name=zhangsan HTTP/1.1 获取请求方式 GET String getMethod() 获取虚拟目录 /day14 String getContextPath() 获取Servlet路径 /demo1 String getServletPath() 获取get方式请求参数 name=zhangsan String getQueryString() 获取请求URI: /day14/demo1 获取协议及版本:HTTP/1.1 String getProtocol 获取客户机的IP地址: String getRemoteAddr()
2. 获取请求头数据方法: 3. 获取请求体数据请求体:只有post请求方式,才有请求体,在请求体中封装post请求的请求参数 步骤: 4. 其他功能4.1获取请求参数通用方式String getParameter(String name) 根据参数名称获取参数值 String[] getParameterValues(String name) 根据参数名称获取参数值的数组,常见复选框 Enumeration<String> getParameterNames() 获取所有请求的参数名称 Map<String, String[]> getParameterMap() 获取所有参数的map集合
4.2 请求转发一种在服务器内部的资源跳转方式 请求次数:代表的是浏览器到服务器端的次数,不包含服务器内部跳转 步骤: 通过request对象获取请求转发器对象:RequestDispatcher getRequestDispatcher(String path) 使用RequestDispatcher对象来进行转发:forward(ServletRequest request,ServletResponse response)
特点: 浏览器地址栏路径不发生变化 只能转发到当前服务器内部资源中 转发是一次请求
4.3 共享数据4.4 获取ServletContext3. request案例1. 用户登录案例需求:
1.编写login.html登录页面
username & password 两个输入框
2.使用Druid数据库连接池技术,操作mysql,day14数据库中user表
3.使用JdbcTemplate技术封装JDBC
4.登录成功跳转到SuccessServlet展示:登录成功!用户名,欢迎您
5.登录失败跳转到FailServlet展示:登录失败,用户名或密码错误
2. 分析file://C:/Users/Lenovo/Desktop/java%E5%9F%BA%E7%A1%80%E5%BF%85%E8%83%8C%E7%9F%A5%E8%AF%86%E7%82%B9/img/%E6%A1%88%E4%BE%8B%E5%88%86%E6%9E%90.png?lastModify=1553751539 3. 开发步骤创建项目,导入HTML项目,配置文件,jar包 创建数据库环境
CREATE DATABASE day14;
USE day14;
CREATE TABLE USER(
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(32) UNIQUE NOT NULL,
PASSWORD VARCHAR(32) NOT NULL
);创建包cn.itcast.domain创建类User 创建包cn.itcast.dao 创建类UserDao 操作数据库,提供login的方法 创建工具吧con.itcast.util创建JDBCUtils工具类,使用Druid连接池,获取连接池对象和连接对象
public class JDBCUtils {
private static DataSource ds;
static {
try {
// 加载配置文件
Properties pro = new Properties();
InputStream in = JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties");
pro.load(in);
// 初始化连接池对象
ds = DruidDataSourceFactory.createDataSource(pro);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
// 获取连接池对象
public static DataSource getDataSource(){
return ds;
}
// 获取连接connection对象
public static Connection getConnection() throws SQLException {
return ds.getConnection();
}
}完善UserDao的方法
public class UserDao {
// 声明JDBCTemplate对象共用
private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
/**
* 登录方法
* @param loginUser 只有用户名和密码
* @return user包含用户全部数据,没有,返回null值
*/
public User login(User loginUser){
try {
// 1. 编写SQL
String sql = "select * from user where username = ? and password = ?";
// 2. 调用query方法
User user = template.queryForObject(sql, new BeanPropertyRowMapper<User>(User.class), loginUser.getUsername(), loginUser.getPassword());
return user;
} catch (DataAccessException e) {
e.printStackTrace();//记录日志
return null;
}
} }
7. 测试方法,看Dao代码运行是否正常,创建包`cn.itcast.test`,测试类`UserDaoTest`
```java
public class UserDaoTest {
@Test
public void testLogin(){
// 创建登录用户对象
User loginUser = new User();
loginUser.setUsername("superbaby");
loginUser.setPassword("123111");
// 查看数据库是否有该对象
UserDao dao = new UserDao();
User user = dao.login(loginUser);
System.out.println(user);
}
} 发现问题,如果用户名密码不一致,会出现异常,不应该抛出异常,应该返回null,用try/catch包裹(ctrl+alt+t) @WebServlet("/successServlet") public class SuccessServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获取request域中共享的user对象
User user =(User) request.getAttribute("user");
if (user!=null) {
// 给页面写一句话
// 设置编码
response.setContentType("text/html;charset=utf-8");
// 输出
response.getWriter().write("登录成功,"+user.getUsername()+"欢迎您!");
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
} }
### 4. 错误日志
问题:登录后跳转找不到网页,转不到loginServlet的页面
解决方法:部署的问题,在idea该项目的部署中,将虚拟目录改为`/day14_test`,之前误改为`/day14`
### 5. 优化
使用Apache的BeanUtils包封装loginUser对象,修改部分如下
```java
/*// 获取请求参数
String username = request.getParameter("username");
String password = request.getParameter("password");
// 封装user对象
User loginUser = new User();
loginUser.setUsername(username);
loginUser.setPassword(password);*/
// 2. 获取所有请求参数
Map<String, String[]> map = request.getParameterMap();
// 3. 创建User对象
User loginUser = new User();
// 3.2 使用BeanUtils封装
try {
BeanUtils.populate(loginUser,map);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}6. BeanUtils工具类简化数据封装,用于封装JavaBean,原理:内省机制 1. J
|