TomCat
web相关概念回顾
1. 软件架构 1. C/S:客户端/服务器端 2. B/S:浏览器/服务器端 2. 资源分类 1. 静态资源:所有用户访问后,得到的结果都是一样的,称为静态资源.静态资源可以直接被浏览器解析 * 如: html,css,JavaScript 2. 动态资源:每个用户访问相同资源后,得到的结果可能不一样。称为动态资源。动态资源被访问后,需要先转换为静态资源,在返回给浏览器 * 如:servlet/jsp,php,asp....
3. 网络通信三要素 1. IP:电子设备(计算机)在网络中的唯一标识。 2. 端口:应用程序在计算机中的唯一标识。 0~65536 3. 传输协议:规定了数据传输的规则 1. 基础协议: 1. tcp:安全协议,三次握手。 速度稍慢 2. udp:不安全协议。 速度快
web服务器软件:
* 服务器:安装了服务器软件的计算机 * 服务器软件:接收用户的请求,处理请求,做出响应 * web服务器软件:接收用户的请求,处理请求,做出响应。 * 在web服务器软件中,可以部署web项目,让用户通过浏览器来访问这些项目 * web容器
* 常见的java相关的web服务器软件: * webLogic:oracle公司,大型的JavaEE服务器,支持所有的JavaEE规范,收费的。 * webSphere:IBM公司,大型的JavaEE服务器,支持所有的JavaEE规范,收费的。 * JBOSS:JBOSS公司的,大型的JavaEE服务器,支持所有的JavaEE规范,收费的。 * Tomcat:Apache基金组织,中小型的JavaEE服务器,仅仅支持少量的JavaEE规范servlet/jsp。开源的,免费的。
* JavaEE:Java语言在企业级开发中使用的技术规范的总和,一共规定了13项大的规范 * Tomcat:web服务器软件 1. 下载:http://tomcat.apache.org/ 2. 安装:解压压缩包即可。 * 注意:安装目录建议不要有中文和空格 3. 卸载:删除目录就行了 4. 启动: * bin/startup.bat ,双击运行该文件即可 * 访问:浏览器输入:http://localhost:8080 回车访问自己 http://别人的ip:8080 访问别人 * 可能遇到的问题: 1. 黑窗口一闪而过: * 原因: 没有正确配置JAVA_HOME环境变量 * 解决方案:正确配置JAVA_HOME环境变量 2. 启动报错: 1. 暴力:找到占用的端口号,并且找到对应的进程,杀死该进程 * netstat -ano 2. 温柔:修改自身的端口号 * conf/server.xml * <Connector port="8888" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8445" /> * 一般会将tomcat的默认端口号修改为80。80端口号是http协议的默认端口号。 * 好处:在访问时,就不用输入端口号 5. 关闭: 1. 正常关闭: * bin/shutdown.bat * ctrl+c 2. 强制关闭: * 点击启动窗口的× 6. 配置: * 部署项目的方式: 1. 直接将项目放到webapps目录下即可。 * /hello:项目的访问路径-->虚拟目录 * 简化部署:将项目打成一个war包,再将war包放置到webapps目录下。 * war包会自动解压缩 2. 配置conf/server.xml文件 在<Host>标签体中配置 <Context docBase="D:\hello" path="/hehe" /> * docBase:项目存放的路径 * path:虚拟目录 3. 在conf\Catalina\localhost创建任意名称的xml文件。在文件中编写 <Context docBase="D:\hello" /> * 虚拟目录:xml文件的名称 * 静态项目和动态项目: * 目录结构 * java动态项目的目录结构: -- 项目的根目录 -- WEB-INF目录: -- web.xml:web项目的核心配置文件 -- classes目录:放置字节码文件的目录 -- lib目录:放置依赖的jar包
-
将Tomcat集成到IDEA中,并且创建JavaEE的项目,部署项目。
ieda配置tomcat
IDEA会为每一个tomcat部署的项目单独建立一份配置文件
查看控制台的log:Using CATALINA_BASE: "C:\Users\fqy.IntelliJIdea2018.1\system\tomcat_itcast"
工作空间项目 和 tomcat部署的web项目
tomcat真正访问的是“tomcat部署的web项目”,"tomcat部署的web项目"对应着"工作空间项目" 的web目录下的所有资源
WEB-INF目录下的资源不能被浏览器直接访问。
断点调试:使用"小虫子"启动 dubug 启动
乱码:
D:\apache\apache-tomcat-9.0.53\conf
logging.properties
java.util.logging.ConsoleHandler.encoding = UTF-8 -> GBK
或者:
idea help VM 加 -Dfile.encoding=UTF-8
(cmd亦然乱码)
*Servlet:服务器
Servlet(程序): server applet
概念:运行在服务器端的小程序
Servlet就是一个接口,定义了Java类被浏览器访问到(tomcat识别)的规则。
将来我们自定义一个类,实现Servlet接口,复写方法。
<!--配置Servlet --> <servlet> <servlet-name>demo1</servlet-name> <servlet-class>cn.itcast.web.servlet.ServletDemo1</servlet-class> </servlet> <servlet-mapping> <servlet-name>demo1</servlet-name> <url-pattern>/demo1</url-pattern> </servlet-mapping>* 步骤: 1. 创建JavaEE项目,选择Servlet的版本3.0以上,可以不创建web.xml 2. 定义一个类,实现Servlet接口 3. 复写方法 4. 在类上使用@WebServlet注解,进行配置 * @WebServlet("资源路径") @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface WebServlet { String name() default "";//相当于<Servlet-name> String[] value() default {};//代表urlPatterns()属性配置 String[] urlPatterns() default {};//相当于<url-pattern> int loadOnStartup() default -1;//相当于<load-on-startup> WebInitParam[] initParams() default {}; boolean asyncSupported() default false; String smallIcon() default ""; String largeIcon() default ""; String description() default ""; String displayName() default ""; }
执行原理:
执行原理:
1. 当服务器接受到客户端浏览器的请求后,会解析请求URL路径,获取访问的Servlet的资源路径 2. 查找web.xml文件,是否有对应的<url-pattern>标签体内容。 3. 如果有,则在找到对应的<servlet-class>全类名 4. tomcat会将字节码文件加载进内存,并且创建其对象 5. 调用其方法 1.解析请求路径 2.将路径中的/demo1 ,去和web.xml配置文件中的<url-pattern>内容进行匹配 3.如果匹配上了就会访问<servlet-class>体指向的servlet
生命周期:
Servlet中的生命周期方法:
被创建:执行init方法,只执行一次
Servlet什么时候被创建?
默认情况下,第一次被访问时,Servlet被创建
可以配置执行Servlet的创建时机。
在<servlet>标签下配置
第一次被访问时,创建
<load-on-startup>的值为负数
在服务器启动时,创建 * <load-on-startup>的值为0或正整数
Servlet的init方法,只执行一次,说明一个Servlet在内存中只存在一个对象,Servlet是单例的
多个用户同时访问时,可能存在线程安全问题。
解决:尽量不要在Servlet中定义成员变量。即使定义了成员变量,也不要对修改值
提供服务:执行service方法,执行多次
每次访问Servlet时,Service方法都会被调用一次。
被销毁:执行destroy方法,只执行一次
Servlet被销毁时执行。服务器关闭时,Servlet被销毁
只有服务器正常关闭时,才会执行destroy方法。
destroy方法在Servlet被销毁之前执行,一般用于释放资源
体系结构
Servlet的体系结构
Servlet -- 接口 | GenericServlet -- 抽象类 | *** HttpServlet -- 抽象类
GenericServlet:将Servlet接口中其他的方法做了默认空实现,只将service()方法作为抽象
将来定义Servlet类时,可以继承GenericServlet,实现service()方法即可
HttpServlet:对http协议的一种封装,简化操作
定义类继承HttpServlet
复写doGet/doPost方法
相关配置
Servlet相关配置
1. urlpartten:Servlet访问路径 2. 一个Servlet可以定义多个访问路径 : @WebServlet({"/d4","/dd4","/ddd4"}) 3. 路径定义规则: 1. /xxx:路径匹配 2. /xxx/xxx:多层路径,目录结构 3. *.do:扩展名匹配
Servlet执行原理:
*HTTP:
概念:Hyper Text Transfer Protocol 超文本传输协议 * 传输协议:定义了,客户端和服务器端通信时,发送数据的格式 * 特点: 1. 基于TCP/IP的高级协议 2. 默认端口号:80 3. 基于请求/响应模型的:一次请求对应一次响应 4. 无状态的:每次请求之间相互独立,不能交互数据
历史版本:
1.0:每一次请求响应都会建立新的连接
1.1:复用连接
请求消息数据格式
请求消息数据格式
请求行 请求方式 请求url 请求协议/版本 GET /login.html HTTP/1.1
请求方式:
HTTP协议有7中请求方式,常用的有2种
GET:
请求参数在请求行中,在url后。
请求的url长度有限制的
不太安全
POST:
请求参数在请求体中
请求的url长度没有限制的
相对安全
请求头:客户端浏览器告诉服务器一些信息 请求头名称: 请求头值
常见的请求头:
User-Agent:浏览器告诉服务器,我访问你使用的浏览器版本信息
可以在服务器端获取该头的信息,解决浏览器的兼容性问题
Referer:http://localhost/login.html
告诉服务器,我(当前请求)从哪里来?
作用:
防盗链:
统计工作:
请求空行 空行,就是用于分割POST请求的请求头和请求体的。
请求体(正文):
封装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: 1例:username=zhangsan
响应消息数据格式
响应消息数据格式
响应消息:服务器端发送给客户端的数据
响应行
格式:协议/版本 响应状态码 状态码描述
响应状态码:服务器告诉客户端浏览器本次请求和响应的一个状态。
状态码都是3位数字
分类:
1xx:服务器就收客户端消息,但没有接受完成,等待一段时间后,发送1xx多状态码
2xx:成功。代表:200
3xx:重定向。代表:302(重定向),304(访问缓存)
4xx:客户端错误。
代表:
404(请求路径没有对应的资源)
405:请求方式没有对应的doXxx方法
5xx:服务器端错误。代表:500(服务器内部出现异常)
响应头:服务器告诉客户端的一些信息
格式:头名称: 值
常见的响应头:
Content-Type:服务器告诉客户端本次响应体数据格式以及编码格式
Content-disposition:服务器告诉客户端以什么格式打开响应体数据
值:
in-line:默认值,在当前页面内打开
attachment;filename=xxx:以附件形式打开响应体。文件下载
响应空行
响应体:传输的数据
* 响应字符串格式 HTTP/1.1 200 OK Content-Type: text/html;charset=UTF-8 Content-Length: 101 Date: Wed, 06 Jun 2018 07:08:42 GMT <html> <head> <title>$Title$</title> </head> <body> hello , response </body> </html>
*Request(请求):
②如果把变量放到request里,就说明它的作用域是request,它的有效范围是当前请求周期。 所谓请求周期:就是从Http请求发起,到服务器处理结束,返回响应的整个过程。在这个过程中可能使用forward的方式跳转了多个JSP页面,在这些页面里,你都可以使用这个变量。
操作基础信息:头、行、体
request对象和response对象的原理
request和response对象是由服务器创建的。我们来使用它们
request对象是来获取请求消息,
response对象是来设置响应消息
request对象继承体系结构: ServletRequest -- 接口 | 继承 HttpServletRequest -- 接口 | 实现 org.apache.catalina.connector.RequestFacade 类(tomcat)
request功能:
获取请求消息数据
获取请求行数据
GET /day14/demo3?name=lisi HTTP/1.1
方法: 获取请求方式 :GET String getMethod() (*)获取虚拟目录:/ String getContextPath() 获取Servlet路径: /demo1 String getServletPath() 获取get方式请求参数:name=zhangsan String getQueryString() (*)获取请求URI:/day14/demo3 String getRequestURI() (*)获取请求URL:http://localhost/day14/demo1 StringBuffer getRequestURL() 获取协议及版本:HTTP/1.1 String getProtocol() 获取客户机的IP地址:192.168.157.53 String getRemoteAddr()
获取请求头数据
方法:->迭代。.hasMoreElements
Enumeration<String> getHeaderNames():获取所有的请求头名称
String getHeader(String name):通过请求头的名称获取请求头的值
获取请求体数据:
请求体:只有POST请求方式,才有请求体,在请求体中封装了POST请求的请求参数
步骤:
获取流对象
BufferedReader getReader():获取字符输入流,只能操作字符数据
ServletInputStream getInputStream():获取字节输入流,可以操作所有类型数据
在文件上传知识点后讲解
再从流对象中拿数据
操作请求参数&转发:
中文乱码问题:
get方式:tomcat 8 已经将get方式乱码问题解决了
post方式:会乱码
解决:在获取参数前,设置request的编码request.setCharacterEncoding("utf-8");
获取请求参数通用方式:不论get还是post请求方式都可以使用下列方法来获取请求参数
String getParameter(String name):根据参数名称获取参数值 username=zs&password=123
String[] getParameterValues(String name):根据参数名称获取参数值的数组 hobby=xx&hobby=game
Enumeration<String> getParameterNames():获取所有请求的参数名称
Map<String,String[]> getParameterMap():获取所有参数的map集合
请求转发:一种在服务器内部的资源跳转方式
使用:
通过request对象获取请求转发器对象:RequestDispatcher getRequestDispatcher(String path)
使用RequestDispatcher对象来进行转发:forward(ServletRequest request, ServletResponse response)
例:request.getRequestDispatcher("/demo9").forward(request,response);
特点:
request是表示一个请求,只要发出一个请求就会创建一个request,它的
用处:常用语服务器间同一请求不同页面之间的参数传递,常用语表单的控件值传递。
1. 浏览器**地址栏路径不发生变化** 2. 只能转发到当前**服务器内部资源**中。 3. 转发是**一次请求** 4. **作用域仅在当前请求中有效。**
共享数据:
域对象:一个有作用范围的对象,可以在范围内共享数据
request域对象:代表一次请求的范围,一般用于请求转发的多个资源中共享数据
方法:
void setAttribute(String name,Object obj):存储数据
Object getAttitude(String name):通过键获取值
void removeAttribute(String name):通过键移除键值对
获取ServletContext:
ServletContext getServletContext()
获取ServletContext域对象
BeanUtils:封装JavaBean的,简化数据封装操作
方法名称 | 方法介绍 | |
---|---|---|
void | setProperty(Object bean,String name,Object value) | 设置属性值 |
Object | getProperty(Object bean,String name) | 获取属性值 |
void | populate(Object obj , Map map) | 将map集合的键值对信息,封装到对应的JavaBean对象中 |
案例:用户登录
用户登录案例需求:
1.编写login.html登录页面 username & password 两个输入框 2.使用Druid数据库连接池技术,操作mysql,day14数据库中user表 3.使用JdbcTemplate技术封装JDBC 4.登录成功跳转到SuccessServlet展示:登录成功!用户名,欢迎您 5.登录失败跳转到FailServlet展示:登录失败,用户名或密码错误
* 分析 * 开发步骤 1. 创建项目,导入html页面,配置文件,jar包 2. 创建数据库环境 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 ); 3. 创建包cn.itcast.domain,创建类User package cn.itcast.domain; /** * 用户的实体类 */ public class User { private int id; private String username; private String password; 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 getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", password='" + password + '\'' + '}'; } } 4. 创建包cn.itcast.util,编写工具类JDBCUtils package cn.itcast.util; import com.alibaba.druid.pool.DruidDataSourceFactory; import javax.sql.DataSource; import javax.xml.crypto.Data; import java.io.IOException; import java.io.InputStream; import java.sql.Connection; import java.sql.SQLException; import java.util.Properties; /** * JDBC工具类 使用Durid连接池 */ public class JDBCUtils { private static DataSource ds ; static { try { //1.加载配置文件 Properties pro = new Properties(); //使用ClassLoader加载配置文件,获取字节输入流 InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties"); pro.load(is); //2.初始化连接池对象 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(); } } 5. 创建包cn.itcast.dao,创建类UserDao,提供login方法 package cn.itcast.dao; import cn.itcast.domain.User; import cn.itcast.util.JDBCUtils; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; /** * 操作数据库中User表的类 */ 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; } } } 6. 编写cn.itcast.web.servlet.LoginServlet类 package cn.itcast.web.servlet; import cn.itcast.dao.UserDao; import cn.itcast.domain.User; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @WebServlet("/loginServlet") public class LoginServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //1.设置编码 req.setCharacterEncoding("utf-8"); //2.获取请求参数 String username = req.getParameter("username"); String password = req.getParameter("password"); //3.封装user对象 User loginUser = new User(); loginUser.setUsername(username); loginUser.setPassword(password); //4.调用UserDao的login方法 UserDao dao = new UserDao(); User user = dao.login(loginUser); //5.判断user if(user == null){ //登录失败 req.getRequestDispatcher("/failServlet").forward(req,resp); }else{ //登录成功 //存储数据 req.setAttribute("user",user); //转发 req.getRequestDispatcher("/successServlet").forward(req,resp); } } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doGet(req,resp); } } 7. 编写FailServlet和SuccessServlet类 @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()+",欢迎您"); } } @WebServlet("/failServlet") public class FailServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //给页面写一句话 //设置编码 response.setContentType("text/html;charset=utf-8"); //输出 response.getWriter().write("登录失败,用户名或密码错误"); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request,response); } }
8. login.html中form表单的action路径的写法 * 虚拟目录+Servlet的资源路径 9. BeanUtils工具类,简化数据封装 * 用于封装JavaBean的 1. JavaBean:标准的Java类 1. 要求: 1. 类必须被public修饰 2. 必须提供空参的构造器 3. 成员变量必须使用private修饰 4. 提供公共setter和getter方法 2. 功能:封装数据 2. 概念: 成员变量: 属性:setter和getter方法截取后的产物 例如:getUsername() --> Username--> username 3. 方法: populate(Object obj , Map map):将map集合的键值对信息,封装到对应的JavaBean对象中
*Response(响应):
设置响应消息
response.sendRedirect("/day15/responseDemo2");重定向:
功能:设置响应消息 1. 设置响应行 1. 格式:HTTP/1.1 200 ok 2. 设置状态码:setStatus(int sc)
设置响应头: setHeader(String name, String value) ,文件属性名
Content-Type text/html;charset=UTF-8 *文件属性类型/拓展名*;
例:response.setHeader("Content-Type", "text/html;charset=UTF-8");
响应对象.设置响应头(“头”,“文件类型/拓展名;字段=字段值”)
文件下载需要的响应头:
String mimeType = servletContext.getMimeType(realPath); response.setHeader("content-type",mimeType); response.setHeader("content-disposition","attachment;filename="+filename);设置响应体:
获取输出流
字符输出流:PrintWriter getWriter()
字节输出流:ServletOutputStream getOutputStream()
使用输出流,将数据输出到客户端浏览器
response.getWriter().write("2思密达");
response.getOutputStream().println("2思密达");
乱码问题:
PrintWriter pw = response.getWriter();获取的流的默认编码是ISO-8859-1
设置该流的默认编码
告诉浏览器响应体使用的编码
//简单的形式,设置编码,是在获取流之前设置 response.setContentType("text/html;charset=utf-8");
完成重定向
重定向:资源跳转的方式
代码实现: //1. 设置状态码为302 response.setStatus(302); //2.设置响应头location response.setHeader("location","/day15/responseDemo2"); //简单的重定向方法 response.sendRedirect("/day15/responseDemo2");
dis请求和转发
*面试题: forward 和 redirect 区别
重定向的特点:redirect
地址上显示的是最后的那个资源的路径地址
请求次数最少有两次, 服务器在第一次请求后,会返回302 以及一个地址, 浏览器在根据这个地址,执行第二次访问。
可以跳转到任意路径。 不是自己的工程也可以跳。
效率稍微低一点, 执行两次请求。
后续的请求,没法使用上一次的request对象,因为这是两次不同的请求。
转发的特点:forward
地址上显示的是请求servlet的地址。 返回200 ok
请求次数只有一次, 因为是服务器内部帮客户端执行了后续的工作。
只能跳转自己项目的资源路径 。
效率上稍微高一点,因为只执行一次请求。
可以使用上一次的request对象。 带着数据走
区别 转发forward() 重定向sendRedirect() 根目录 包含项目访问地址 没有项目访问地址 地址栏 不会发生变化 会发生变化 哪里跳转 服务器端进行的跳转 浏览器端进行的跳转 请求域中数据 不会丢失 会丢失 如果要保留请求域中的数据,使用转发,否则使用重定向。
以后访问数据库,增删改使用重定向,查询使用转发。
路径分类
相对路径:通过相对路径不可以确定唯一资源
如:./index.html
不以/开头,以.开头路径
规则:找到当前资源和目标资源之间的相对位置关系
./:当前目录
../:后退一级目录
绝对路径:通过绝对路径可以确定唯一资源
如:http://localhost/day15/responseDemo2 /day15/responseDemo2
以/开头的路径
规则:判断定义的路径是给谁用的?判断请求将来从哪儿发出
给客户端浏览器使用:需要加虚拟目录(项目的访问路径)
建议虚拟目录动态获取:request.getContextPath()
<a> , <form> 重定向...
给服务器使用:不需要加虚拟目录
转发路径
请求:重定向(2)&转发(1)
ServletContext(域:Web应用):
④如果把变量放到application里,就说明它的作用域是application,它的有效范围是整个应用。所谓整个应用:是指从应用启动到应用结束。application里的变量存活时间最长,如果不进行手动删除,它们就一直可以使用。
概念:代表整个web应用,可以和程序的容器(服务器)来通信
作用范围:所有的用户都可以取得此信息,此信息在整个服务器端被保留。
Application属性范围值只要设置一次,则所有的网页窗口都可以取得数据。
ServletContext在服务器启动时创建,在服务器关闭时销毁,
一个JavaWeb应用只创建一个ServletContext对象。
获取:
通过request对象获取 request.getServletContext();
通过HttpServlet获取
this.getServletContext();
功能:
String getMimeType(String file) MIME类型:在互联网通信过程中定义的一种文件数据类型 获取MIME类型:大类型/小类型 text/html image/jpeg 1. setAttribute(String name,Object value) 2. getAttribute(String name) 设置,获取,数据 域对象:共享数据 3. removeAttribute(String name) 删除数据 ServletContext() 对象范围:所有用户所有请求的数据 对象范围:所有用户所有请求的数据 String getRealPath(String path) String b = context.getRealPath("/b.txt");//web目录下资源访问 获取文件的真实(服务器)路径 String c = context.getRealPath("/WEB-INF/c.txt");//WEB-INF目录下的资源访问 String a = context.getRealPath("/WEB-INF/classes/a.txt");//src目录下的资源访问 InputStream getResourceAsStream(String path) InputStream is= getResourceAsStream(String path) 获取项目下文件的输入流
案例:文件下载
* 文件下载需求: 1. 页面显示超链接 2. 点击超链接后弹出下载提示框 3. 完成图片文件下载 //1.获取请求参数 String filename = request.getParameter("filename"); //2.获取要下载的文件在服务器的真实位置 ServletContext servletContext = request.getServletContext(); String realPath = servletContext.getRealPath("/imgs/"+filename); //响应头 //图片文件类型 String mimeType = servletContext.getMimeType(realPath); response.setHeader("content-type",mimeType); response.setHeader("content-disposition","attachment;filename="+filename); //3.创建输入流 //BufferedInputStream bis = new BufferedInputStream(new FileInputStream(realPath)); BufferedInputStream bis = new BufferedInputStream(servletContext.getResourceAsStream(realPath)); //4.输出流 BufferedOutputStream bos = new BufferedOutputStream( response.getOutputStream()); //ServletOutputStream sos = response.getOutputStream(); //流操作 byte[] bytes = new byte[1024]; int len; while ((len=bis.read(bytes))!=-1){ bos.write(bytes,0,len); } bis.close(); } * 分析: 1. 超链接指向的资源如果能够被浏览器解析,则在浏览器中展示,如果不能解析,则弹出下载提示框。不满足需求 2. 任何资源都必须弹出下载提示框 3. 使用响应头设置资源的打开方式: * content-disposition:attachment;filename=xxx * 步骤: 1. 定义页面,编辑超链接href属性,指向Servlet,传递资源名称filename 2. 定义Servlet 1. 获取文件名称 2. 使用字节输入流加载文件进内存 3. 指定response的响应头: content-disposition:attachment;filename=xxx 4. 将数据写出到response输出流
* 问题: * 中文文件问题 * 解决思路: 1. 获取客户端使用的浏览器版本信息 2. 根据不同的版本信息,设置filename的编码方式不同
验证码:
package com.hpit.web; import javax.imageio.ImageIO; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.awt.*; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.Random; @WebServlet("/CheckCodeServlet") public class CheckCodeServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { int width = 100; int height = 50; //1.创建一对象,在内存中图片(验证码图片对象) BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB); //2.美化图 //2.1 填充背景色 Graphics g = image.getGraphics();//画笔对象 g.setColor(Color.PINK);//设置画笔颜色 g.fillRect(0,0,width,height); //2.2画边框 g.setColor(Color.BLUE); g.drawRect(0,0,width - 1,height - 1); String str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghigklmnopqrstuvwxyz0123456789"; //生成随机角标 Random ran = new Random(); for (int i = 1; i <= 4; i++) { int index = ran.nextInt(str.length()); //获取字符 char ch = str.charAt(index);//随机字符 //2.3写验证码 g.drawString(ch+"",width/5*i,height/2); } //2.4画干扰线 g.setColor(Color.GREEN); //随机生成坐标点 for (int i = 0; i < 10; i++) { int x1 = ran.nextInt(width); int x2 = ran.nextInt(width); int y1 = ran.nextInt(height); int y2 = ran.nextInt(height); g.drawLine(x1,y1,x2,y2); } //3.将图片输出到页面展示 ImageIO.write(image,"jpg",response.getOutputStream()); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request,response); } }
Cookie&Session
会话技术:
1. 会话:一次会话中包含多次请求和响应。 * 一次会话:浏览器第一次给服务器资源发送请求,会话建立,直到有一方断开为止 2. 功能:在一次会话的范围内的多次请求间,共享数据 3. 方式: 1. 客户端会话技术:Cookie 2. 服务器端会话技术:Session
Cookie:
概念:客户端会话技术,将数据保存到客户端
快速入门:
使用步骤:
创建Cookie对象,绑定数据
new Cookie(String name, String value)
发送Cookie对象
response.addCookie(Cookie cookie)
获取Cookie,拿到数据
Cookie[] request.getCookies()
实现原理
基于响应头set-cookie和请求头cookie实现
查找cookie:
public static Cookie findCookie(Cookie[] cookies,String name){ //判断cookie不为null并且长度大于0 if(cookies!=null && cookies.length>0){ //遍历cookie数组查找cookie for (Cookie cookie : cookies) { //找到了指定名称的cookie if(name.equals(cookie.getName())){ return cookie; } } } return null ; }
细节:
cookie的细节
cookie在浏览器中的保存时间:
默认情况下,当浏览器关闭后,Cookie数据被销毁
持久化存储:
setMaxAge(int seconds)
正数:将Cookie数据写到硬盘的文件中。持久化存储。并指定cookie存活时间,时间到后,cookie文件自动失效
负数:默认值
零:删除cookie信息
cookie存中文:
在tomcat 8 之前 cookie中不能直接存储中文数据。
需要将中文数据转码---一般采用URL编码(%E3)
在tomcat 8 之后,cookie支持中文数据。特殊字符还是不支持,建议使用URL编码存储,URL解码解析
cookie共享问题?演示***
同个tomcat服务器中,部署了多个web项目
默认情况下cookie不能共享
setPath(String path):设置cookie的获取范围。默认情况下,设置当前的虚拟目录
如果要共享,则可以将path设置为"/"
不同的tomcat服务器间cookie共享问题
setDomain(String path):如果设置一级域名相同,那么多个服务器之间cookie可以共享
setDomain(".baidu.com"),那么tieba.baidu.com和news.baidu.com中cookie可以共享
Cookie的特点和作用
特点:
cookie存储数据在客户端浏览器
浏览器对于单个cookie 的大小有限制(4kb) 以及 对同一个域名下的总cookie数量也有限制(20个)
作用:
cookie一般用于存储少量的不太敏感的数据
在不登录的情况下,完成服务器对客户端的身份识别
案例:判断用户是否第一次登陆
@WebServlet("/lastVisit") public class LastVisitServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //解决中文乱码问题 response.setContentType("text/html;charset=utf-8"); //判断用户是否是第一次访问 lastVisit Cookie[] cookies = request.getCookies();//[username=zs,password=123,lastVisit=2018-10-01] //查找cookie Cookie cookie = CookieUtils.findCookie(cookies, "lastVisit"); //判断用户是否是第一次访问 //第一次访问 if(cookie==null){ response.getWriter().write("欢迎您第一次访问"); }else{ //不是第一次访问 //获取cookie中保存的时间 String value = cookie.getValue(); response.getWriter().write("您上次的访问时间是:"+value); } //不论用户是否是第一次访问,都需要更新Cookie信息 //更新cookie信息 //获取当年前时间字符串 Date now = new Date(); SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String time = format.format(now); //创建cookie Cookie lastVisit = new Cookie("lastVisit", time); //设置cookie的存活时间 lastVisit.setMaxAge(2*24*60*60); //响应到客户端 response.addCookie(lastVisit); } }
JSP:
概念:
Java Server Pages: java服务器端页面
一个特殊的页面,其中既可以指定定义html标签,又可以定义java代码,用于简化书写!!!
原理
JSP本质上就是一个Servlet
JSP的脚本:JSP定义Java代码的方式
<% 代码 %>:定义的java代码,在service方法中。service方法中可以定义什么,该脚本中就可以定义什么。
<%! 代码 %>:定义的java代码,在jsp转换后的java类的成员位置。
<%= 代码 %>:定义的java代码,会输出到页面上。输出语句中可以定义什么,该脚本中就可以定义什么。
JSP的内置对象:
在jsp页面中不需要获取和创建,可以直接使用的对象
jsp一共有9个内置对象。
基础3个:
request
response
out:字符输出流对象。可以将数据输出到页面上。和response.getWriter()类似
response.getWriter()和out.write()的区别:
在tomcat服务器真正给客户端做出响应之前,会先找response缓冲区数据,再找out缓冲区数据。
response.getWriter()数据输出永远在out.write()之前
Session:
③如果把这个变量放到session里,就说明它的作用域是session,它的有效范围是当前会话。 所谓当前会话:就是指从用户打开浏览器开始,知道用户关闭浏览器这中间的过程,这个过程可能包含多个请求响应。 也就是说,只要用户不关闭浏览器,服务器就有办法知道这些请求是一个人发起的,整个过程被称为一个会话,而放到会话中的变量,就可以在当前会话的所有请求里使用。
概念:服务器端会话技术,在一次会话的多次请求间共享数据,将数据保存在服务器端的对象中。HttpSession
快速入门:
获取HttpSession对象: HttpSession session = request.getSession();
使用HttpSession对象: Object getAttribute(String name) void setAttribute(String name, Object value) void removeAttribute(String name)
原理
Session的实现是依赖于Cookie的。
在一次会话中,客户端向服务端发送一个响应头,创建Session对象,会通过Cookie响应返回一个JsessionID,用于管理此用户对象,
每次请求或响应都会与服务端存储的sessionID判定,没有即第一次访问并创建JsessionID对象,有就调用此对象,
用户数据就会存储在此session中。
细节:
细节:
session的保存时间
服务器关闭
session对象调用invalidate() 。
session默认失效时间 30分钟 选择性配置修改 <session-config> <session-timeout>30</session-timeout> </session-config>
当客户端关闭后,服务器不关闭,两次获取session 不是同一个。 如果需要相同,则可以创建Cookie,键为JSESSIONID,设置最大存活时间,让cookie持久化保存。 例: Cookie c = new Cookie("JSESSIONID",session.getId()); c.setMaxAge(60*60); response.addCookie(c); 客户端不关闭,服务器关闭后,两次获取的session 不是同一个,但是要确保数据不丢失。tomcat自动完成以下工作 session的钝化: 在服务器正常关闭之前,将session对象序列化到硬盘上 session的活化: 在服务器启动后,将session文件转化为内存中的session对象即可。 session的特点
session用于存储一次会话的多次请求的数据,存在服务器端
session可以存储任意类型,任意大小的数据
session与Cookie的区别:
session存储数据在服务器端,Cookie在客户端
session没有数据大小限制,Cookie有
session数据安全,Cookie相对于不安全
案例:验证码
1. 案例需求: 1. 访问带有验证码的登录页面login.jsp 2. 用户输入用户名,密码以及验证码。 * 如果用户名和密码输入有误,跳转登录页面,提示:用户名或密码错误 * 如果验证码输入有误,跳转登录页面,提示:验证码错误 * 如果全部输入正确,则跳转到主页success.jsp,显示:用户名,欢迎您
<%-- Created by IntelliJ IDEA. User: 24836 Date: 2021/9/23 Time: 9:34 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> <link rel="stylesheet" href="css/login.css"> </head> <body> <div id="login-box"> <h1>login</h1> <form method="post" action="/LoginServlet" id="loginfrom"> <div class="form"> <div class="item"> <input type="text" id="uname" value="<%=request.getSession().getAttribute("uname") == null ? "" : request.getSession().getAttribute("uname")%>" name="username" placeholder="Username"/> </div> <div class="item"> <input type="password" id="upwd" value="<%=request.getSession().getAttribute("upwd") == null ? "" :request.getSession().getAttribute("upwd") %>" name="password" placeholder="Password"/> </div> <img src="/CheckCodeServlet" style="display: inline-block" id="login_check"> <p style="color: red"><%=request.getSession().getAttribute("error_check") == null ? "" : request.getSession().getAttribute("error_check")%></p> <p style="color: red"><%=request.getSession().getAttribute("error_user") == null ? "" : request.getSession().getAttribute("error_user")%></p> <div class="item"> <input type="text" id="check" name="check"> </div> <span id="msg" style="font-size: 12px;color: red;line-height: 30px;padding: 0 10px 0 10px;"></span> </div> <input type="button" id="loginBut" class="anliu" name="login" value="Login"/> </form> </div> </body> <script type="text/javascript" src="js/jquery-3.3.1.js"></script> <script src="js/login.js"></script> </html>
package com.login.web; import com.login.dao.AdminDAO; import com.login.pojo.Admin; import org.apache.commons.beanutils.BeanUtils; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.Map; @WebServlet("/LoginServlet") public class LoginServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //乱码 request.setCharacterEncoding("utf-8"); //获取用户输入 Map<String, String[]> parameterMap = request.getParameterMap(); /*String uname = request.getParameter("username"); String upwd = request.getParameter("password");*/ //存 Admin admin = new Admin(); try { BeanUtils.populate(admin, parameterMap); } catch (IllegalAccessException | InvocationTargetException e) { throw new RuntimeException(e); } //获取数据库内对象 AdminDAO adminDAO = new AdminDAO(); Admin loginadmin = adminDAO.loginadmin(admin); //用户输入验证码 //String checkp = request.getParameter("check"); //用户输入验证码 String checkp = parameterMap.get("check")[0]; //3.拿到图片中的验证码 String check = (String) request.getSession().getAttribute("check"); //将session中的验证码销毁 request.getSession().removeAttribute("check"); request.getSession().removeAttribute("error_user"); request.getSession().removeAttribute("error_check"); request.getSession().removeAttribute("uname"); request.getSession().removeAttribute("upwd"); if (checkp.equalsIgnoreCase(check)){ //判断 if (loginadmin!=null){ //用户名或者密码正确 request.getSession().setAttribute("username",loginadmin.getUsername()); //重定向 response.sendRedirect(request.getContextPath()+"/success.jsp"); }else { //用户名或者密码错误 //向request中存入提示信息 request.getSession().setAttribute("error_user","用户名或者密码错误!"); //重定向 response.sendRedirect(request.getContextPath()+"/login.jsp"); } }else { //验证码不同 request.getSession().setAttribute("error_check", "验证码错误"); //重定向 String username = admin.getUsername(); String password = admin.getPassword(); request.getSession().setAttribute("uname", username); request.getSession().setAttribute("upwd", password); response.sendRedirect(request.getContextPath()+"/login.jsp"); } } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } }
Servlet中的四种域对象(转)
pageContext
pageContext作用域为page(页面执行期)。
request
request是表示一个请求,只要发出一个请求就会创建一个request,它的作用域仅在当前请求中有效。
用处:常用语服务器间同一请求不同页面之间的参数传递,常用语表单的控件值传递。
方法:request.setAttribute(); reuqest.getAttribute();
request.removeAttribute(); request.getParameter();
session
服务器会为每一个会话创建一个Session对象,所以Session中的数据可供当前会话中所有Servlet共享。
用处:常用于web开发中的登录验证界面(当用户登陆成功后浏览器分配其中一个Session键值对)。
方法:session.setAttribute(); session.getAttribute();
session.removeAttribute();
Application(ServletContext上下文)
作用范围:所有的用户都可以取得此信息,此信息在整个服务器端被保留。Application属性范围值只要设置一次,则所有的网页窗口都可以取得数据。ServletContext在服务器启动时创建,在服务器关闭时销毁,一个JavaWeb应用只创建一个ServletContext对象。
方法:ServletContext application = this.getServletContext();
application.setAttribute(); application.getAttribute();
application.removeAttribute();
Servlet作用域
例如,我们访问index.jsp的时候,分别对pageContext、request、session、application四个作用域进行累加。
计算完成后就从index.jsp执行forward转发到test.jsp,在test.jsp里再进行一次累加,然后显示出这四个整数来。
从结果来看:
①page里的变量没法从index.jsp传递到test.jsp,只要页面跳转了,它们就不见了。
②request里的变量可以跨越forward前后两页。但是只要刷新页面,它们就重新计算了。
③session和application的变量一直在累加,开始还看不出区别,只要关闭浏览器,再次重启浏览器访问这个页面,session里的变量就重新计算了。
④application里的变量一直在累加,除非你重启Tomcat,否则它会一直变大。
作用域规定的是变量的有效期限
①如果把变量放到pageContext里,就说明它的作用域是page,它的有效范围只在当前JSP页面里。从把变量放到pageContext开始,直到JSP页面跳转前都可以使用。
②如果把变量放到request里,就说明它的作用域是request,它的有效范围是当前请求周期。 所谓请求周期:就是从Http请求发起,到服务器处理结束,返回响应的整个过程。在这个过程中可能使用forward的方式跳转了多个JSP页面,在这些页面里,你都可以使用这个变量。
③如果把这个变量放到session里,就说明它的作用域是session,它的有效范围是当前会话。 所谓当前会话:就是指从用户打开浏览器开始,知道用户关闭浏览器这中间的过程,这个过程可能包含多个请求响应。 也就是说,只要用户不关闭浏览器,服务器就有办法知道这些请求是一个人发起的,整个过程被称为一个会话,而放到会话中的变量,就可以在当前会话的所有请求里使用。
④如果把变量放到application里,就说明它的作用域是application,它的有效范围是整个应用。所谓整个应用:是指从应用启动到应用结束。application里的变量存活时间最长,如果不进行手动删除,它们就一直可以使用。
四种域对象的总结
一、ServletContext
1、生命周期:当Web应用被加载进容器时创建代表整个web应用的ServletContext对象,当服务器关闭或Web应用被移除时,ServletContext对象跟着销毁。
2、作用范围:整个Web应用。
3、作用:
a)在不同Servlet 之间转发
this.getServletContext().getRequestDispatcher("/servlet/Demo10Servlet").forward(request, response);
方法执行结束,service就会返回到服务器,再有服务器去调用目标servlet,其中request会重新创建,并将之前的request的数据拷贝进去。
b)读取资源文件。
1、由于相对路径默认相对的是java虚拟机启动的目录,所以我们直接写相对路径将会是相对于tomcat/bin目录,所以是拿不到资源的。如果写成绝对路径,当项目发布到其他环境时,绝对路径就错了。
2、为了解决这个问题ServletContext提供了:
this.getServletContext().getRealPath("/1.properties"),给进一个资源的虚拟路径,将会返回该资源在当前环境下的真实路径。
this.getServletContext().getResourceAsStream("/1.properties"),给一个资源的虚拟路径返回到该资源真实路径的流。
3、当在非servlet下获取资源文件时,就没有ServletContext对象用了,此时只能用类加载器
classLoader.getResourceAsStream("../../1.properties"),此方法利用类加载器直接将资源加载到内存中,有更新延迟的问题,以及如果文件太大,占用内存过大。
classLoader.getResource("../1.properties").getPath(),直接返回资源的真实路径,没有更新延迟的问题。
二、Request 域
1、生命周期:在service 方法调用前由服务器创建,传入service方法。整个请求结束,request生命结束。
2、作用范围:整个请求链(请求转发也存在)。
3、作用: 在整个请求链中共享数据。最常用到:在Servlet 中处理好的数据交给Jsp显示,此时参数就可以放置在Request域中带过去。
三、Session 域
HttpSession 在服务器中,为浏览器创建独一无二的内存空间,在其中保存会话相关的信息。 1、生命周期:在第一次调用 request.getSession() 方法时,服务器会检查是否已经有对应的session,如果没有就在内存 中创建一个session并返回。
当一段时间内session没有被使用(默认为30分钟),则服务器会销毁该session。
如果服务器非正常关闭(强行关闭),没有到期的session也会跟着销毁。
如果调用session提供的invalidate() ,可以立即销毁session。
注意:服务器正常关闭,再启动,Session对象会进行钝化和活化操作。同时如果服务器钝化的时间在session 默认销毁时间之内,则活化后session还是存在的。否则Session不存在。 如果JavaBean 数据在session钝化时,没有实现Serializable 则当Session活化时,会消失。
2、作用范围:一次会话。
四、PageContext 域
1、生命周期:当对JSP的请求时开始,当响应结束时销毁。
2、作用范围:整个JSP页面,是四大作用域中最小的一个。
作用:
(1)获取其它八大隐式对象,可以认为是一个入口对象。
(2)获取其所有域中的数据
pageContext 操作所有域中属性的方法
public java.lang.Object getAttribute(java.lang.String name,int scope) public void setAttribute(java.lang.String name, java.lang.Object value,int scope)
public void removeAttribute(java.lang.String name,int scope)
pageContext 中代表域的常量
PageContext.APPLICATION_SCOPE
PageContext.SESSION_SCOPE
PageContext.REQUEST_SCOPE
PageContext.PAGE_SCOPE
findAttribute方法,在四大域中搜寻属性,搜寻的顺序是page域、request域、session域、application域,从小域到大域开始搜索,如果搜索到就直接获取该值,如果所有域中都找不到,返回一个null(与el表达式不同,此处返回null,对网页是不友好的)
(3)跳转到其他资源 其身上提供了forward和include方法,简化重定向和转发的操作
ActionContext与ServletActionContext的区别及获取request、session等对象 我们知道struts2接受客户端请求,在Action中进行处理后,将视图结果返回。struts2容器自身不依赖于web容器,不用和servlet对象中的请求(request)、响应(response)进行关联,对于请求的参数,通过paramerInterceptor将参数封装在Action中,然后通过调用get、set方法将参数值设置进Action之中。如果仅仅获取参数,可能有时候满足不了开发的需求,有时我们要获取request或者response中的信息,要对其进行设置、处理。
一、ActionContext
是Action执行的上下文,Action的上下文可以看作是一个容器,里面封装了请求(Request)、会话(Session)、Application等,这里面的Request、Session、Application是Map类型的,往里面封装的是键值对,所以这就体现了struts2不与底层servlet Api打交道,那么对很多web的相关对象进行封装,这样可以达到Action与web层解耦。
用ActionContext得到Map类型的Request、Session、Application。
例子:
获取request: Map request = ActionContext.getContext().get("request"); 往request里封装数据 request.put("name", value); 在前台就可以用request.getAttribute("name");
获取session Map session = ActionContext.getContext().getSession(); 将数据封装到session中 session.put("name", value); 在前台页面上用sessionScope.getAttribute("name");得到session里面封装的值。
得到session、request有点区别,得到request用的是get("reqeust"),得到session用的是getSession()
也可以直接对Java Servlet Http的请求(HttpServletRequest)、响应(HttpServletResponse)操作,和上面的例子有点区别,注意区别。
ActionContext ctx = ActionContext.getContext(); HttpServletRequest request = (HttpServletRequest)ctx.get(ServletActionContext.HTTP_REQUEST); HttpServletResponse response = (HttpServletResponse)ctx.get(ServletActionContext.HTTP_RESPONSE);
用法就和Servlet中的request、response用法一样
二、ServletActionContext
它继承ActionContext,所以ServletActionContext也可以得到HttpServetRequest、HttpServletResponse,,它也提供了直接与Servlet相关对象访问的功能,它可以取得的对象有:
(1)javax.servlet.http.HttpServletRequest : HTTPservlet请求对象
(2)javax.servlet.http.HttpServletResponse : HTTPservlet相应对象
(3)javax.servlet.ServletContext : Servlet上下文信息
(4)javax.servlet.ServletConfig : Servlet配置对象
(5)javax.servlet.jsp.PageContext : Http页面上下文
如何获取HttpRequest、HttpResponse
例子
HttpServletRequest request = ServletActionContext.getRequest();
HttpServletResponse response = ServletActionContext.getResponse();
然后就可以用request.setAttribute("name", value)方法了。
总结:不难看出,两者之间还是存在很多共同功能,那么我们还是根据自己的需求进行选择,能用ActionContext对象满足就尽量使用ActionContext,避免让我们直接去访问Servlet对象。另外,不要在Action还没实例化的时候去通过ActionContext调用方法,因为Action实例在ActionContext实例之前创建,ActionContext中一些值还没有设置,会返回null。
———————————————— 原文链接:JAVA EE 中的域对象总结_朗晴的技术博客-CSDN博客_servlet中的域对象
JSP&EL&JSTL:
JSP:
page
①如果把变量放到pageContext里,就说明它的作用域是page,它的有效范围只在当前JSP页面里。从把变量放到pageContext开始,直到JSP页面跳转前都可以使用。
指令
作用:用于配置JSP页面,导入资源文件
格式: <%@ 指令名称 属性名1=属性值1 属性名2=属性值2 ... %>
指令分类:
page: 配置JSP页面的
contentType:等同于response.setContentType()
设置响应体的mime类型以及字符集
设置当前jsp页面的编码(只能是高级的IDE才能生效,如果使用低级工具,则需要设置pageEncoding属性设置当前页面的字符集)
import:导包
errorPage:当前页面发生异常后,会自动跳转到指定的错误页面
isErrorPage:标识当前是否是错误页面。
true:是,可以使用内置对象exception
false:否。默认值。不可以使用内置对象exception
include : 页面包含的。导入页面的资源文件
<%@include file="top.jsp"%>
taglib : 导入资源
<%@ taglib prefix="c" uri="Oracle Java Technologies | Oracle" %>
prefix:前缀,自定义的
注释:
html注释: <!-- -->:只能注释html代码片段
jsp注释:推荐使用 <%-- --%>:可以注释所有
内置对象
在jsp页面中不需要创建,直接使用的对象
一共有9个:
变量名 真实类型 作用 pageContext PageContext 当前页面共享数据,还可以获取其他八个内置对象 request HttpServletRequest 一次请求访问的多个资源(转发) session HttpSession 一次会话的多个请求间 application ServletContext 所有用户间共享数据 response HttpServletResponse 响应对象 page Object 当前页面(Servlet)的对象 this out JspWriter 输出对象,数据输出到页面上 config ServletConfig Servlet的配置对象 exception Throwable 异常对象
获取相对路径:pageContext.request.contextPath -> (HttpServletRequest.getcontextPath())
MVC:开发模式
jsp演变历史
早期只有servlet,只能使用response输出标签数据,非常麻烦
后来有jsp,简化了Servlet的开发,如果过度使用jsp,在jsp中既写大量的java代码,又写html表,造成难于维护,难于分工协作
再后来,java的web开发,借鉴mvc开发模式,使得程序的设计更加合理性
MVC:
M:Model,模型。JavaBean
完成具体的业务操作,如:查询数据库,封装对象
V:View,视图。JSP
展示数据
C:Controller,控制器。Servlet
获取用户的输入
调用模型
将数据交给视图进行展示
优缺点:
优点:
耦合性低,方便维护,可以利于分工协作,重用性高
缺点:
使得项目架构变得复杂,对开发人员要求高
EL表达式
概念:Expression Language 表达式语言
作用:替换和简化,jsp页面中java代码的编写
语法:${表达式}
注意:
jsp默认支持el表达式的。如果要忽略el表达式
设置jsp中page指令中:isELIgnored="true" 忽略当前jsp页面中所有的el表达式
${表达式} :忽略当前这个el表达式
使用:
使用:
运算符:
算数运算符: + - * /(div) %(mod)
比较运算符: > < >= <= == !=
逻辑运算符: &&(and) ||(or) !(not)
空运算符: empty
功能:用于判断字符串、集合、数组对象是否为null或者长度是否为0
${empty list}:判断字符串、集合、数组对象是否为null或者长度为0
为空就是true;不为空是false
${not empty str}:表示判断字符串、集合、数组对象是否不为null 并且 长度>0
为空就是false;不为空是true
获取值
el表达式只能从域对象中获取值
${域名称.键名}:从指定域中获取指定键的值
* 域名称: 1. pageScope --> pageContext 2. requestScope --> request 3. sessionScope --> session 4. applicationScope --> application(ServletContext) * 举例:在request域中存储了name=张三 * 获取:${requestScope.name}
${键名}:表示依次从最小的域中查找是否有该键对应的值,直到找到为止。
. 获取对象、List集合、Map集合的值
对象:${域名称.键名.属性名}
List集合:${域名称.键名[索引]}
本质上会去调用对象的getter方法
3.Map集合:
${域名称.键名.key名称}
${域名称.键名["key名称"]}
隐式对象:(了解)
el表达式中有11个隐式对象
pageContext:
获取jsp其他八个内置对象
${pageContext.request.contextPath}:动态获取虚拟目录
JSTL
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
概念:JavaServer Pages Tag Library JSP标准标签库
是由Apache组织提供的开源的免费的jsp标签 <标签>
作用:用于简化和替换,jsp页面上的java代码
使用步骤:
导入jstl相关jar包
引入标签库:taglib指令: <%@ taglib %>
使用标签
使用:
常用的JSTL标签
if:相当于java代码的if语句
属性:
test 必须属性,接受boolean表达式
如果表达式为true,则显示if标签体内容,如果为false,则不显示标签体内容
一般情况下,test属性值会结合el表达式一起使用
2. 注意: * c:if标签没有else情况,想要else情况,则可以再定义一个c:if标签
choose:相当于java代码的switch语句
使用choose标签声明 相当于switch声明
使用when标签做判断 相当于case
使用otherwise标签做其他情况的声明 相当于default
foreach:相当于java代码的for语句
练习:
需求:在request域中有一个存有User对象的List集合。需要使用jstl+el将list集合数据展示到jsp页面的表格table中
三层架构:软件设计架构
1. 界面层(表示层):用户看的得界面。用户可以通过界面上的组件和服务器进行交互 2. 业务逻辑层:处理业务逻辑的。 3. 数据访问层:操作数据存储文件。
案例:用户信息列表展示
1. 需求:用户信息的增删改查操作 2. 设计: 1. 技术选型:Servlet+JSP+MySQL+JDBCTempleat+Duird+BeanUtilS+tomcat 2. 数据库设计: 3. 开发: 1. 环境搭建 2. 编码 4. 测试 5. 部署运维
Filter:过滤器
概念:
概念:
web中的过滤器:当访问服务器的资源时,过滤器可以将请求拦截下来,完成一些特殊的功能。
过滤器的作用:
一般用于完成通用的操作。如:登录验证、统一编码处理、敏感字符过滤...
快速入门:
步骤:
定义一个类,实现接口Filter
复写方法
配置拦截路径的方法:
web.xml
注解
实现:
2. 代码: @WebFilter("/*")//访问所有资源之前,都会执行该过滤器 public class FilterDemo1 implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("filterDemo1被执行了...."); //放行 filterChain.doFilter(servletRequest,servletResponse); } @Override public void destroy() { } }
过滤器细节:
web.xml配置 <filter> <filter-name>demo1</filter-name> <filter-class>cn.itcast.web.filter.FilterDemo1</filter-class> </filter> <filter-mapping> <filter-name>demo1</filter-name> <!-- 拦截路径 --> <url-pattern>/*</url-pattern> </filter-mapping>
过滤器执行流程
执行过滤器
执行放行后的资源
回来执行过滤器放行代码下边的代码
过滤器生命周期方法
init:在服务器启动后,会创建Filter对象,然后调用init方法。只执行一次。用于加载资源
doFilter:每一次请求被拦截资源时,会执行。执行多次
destroy:在服务器关闭后,Filter对象被销毁。如果服务器是正常关闭,则会执行destroy方法。只执行一次。用于释放资源
过滤器配置详解
拦截路径配置:
具体资源路径: /index.jsp 只有访问index.jsp资源时,过滤器才会被执行
拦截目录: /user/* 访问/user下的所有资源时,过滤器都会被执行
后缀名拦截: *.jsp 访问所有后缀名为jsp资源时,过滤器都会被执行
拦截所有资源:/* 访问所有资源时,过滤器都会被执行
拦截方式配置:资源被访问的方式
注解配置:
设置dispatcherTypes属性 *1. REQUEST:默认值。浏览器直接请求资源 *2. FORWARD:转发访问资源
INCLUDE:包含访问资源
ERROR:错误跳转资源
ASYNC:异步访问资源
web.xml配置
设置<dispatcher></dispatcher>标签即可
过滤器链(配置多个过滤器)
执行顺序:如果有两个过滤器:过滤器1和过滤器2
过滤器1
过滤器2
资源执行
过滤器2
过滤器1
过滤器先后顺序问题:
注解配置:按照类名的字符串比较规则比较,值小的先执行
如: AFilter 和 BFilter,AFilter就先执行了。
web.xml配置: <filter-mapping>谁定义在上边,谁先执行
案例:
案例1_登录验证
需求:
访问day20_case案例的资源。验证其是否登录
如果登录了,则直接放行。
如果没有登录,则跳转到登录页面,提示"您尚未登录,请先登录"。
案例2_敏感词汇过滤
需求:
对day17_case案例录入的数据进行敏感词汇过滤
敏感词汇参考《敏感词汇.txt》
如果是敏感词汇,替换为 ***
分析:
对request对象进行增强。增强获取参数相关方法
放行。传递代理对象
增强对象的功能:
设计模式:一些通用的解决固定问题的方式
装饰模式
代理模式
概念:
真实对象:被代理的对象
代理对象:
代理模式:代理对象代理真实对象,达到增强真实对象功能的目的
实现方式:
静态代理:有一个类文件描述代理模式
动态代理:在内存中形成代理类
实现步骤:
代理对象和真实对象实现相同的接口
代理对象 = Proxy.newProxyInstance();
使用代理对象调用方法。
增强方法
增强方式:
增强参数列表
增强返回值类型
增强方法体执行逻辑
敏感词案例:
```java @WebFilter("/*") public class MingGanCiHuiFilter implements Filter { //存敏感词汇的集合 private List<String> list = new ArrayList<String>(); public void destroy() { } public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException { //HttpServletRequest req1 = (HttpServletRequest) req; //增强request -->增强request.getParameter() ServletRequest proxy_req = (ServletRequest) Proxy.newProxyInstance( req.getClass().getClassLoader(), //request的类加载器 req.getClass().getInterfaces(), //request的父类接口(干爹们) new InvocationHandler() { //处理器:增强的代码 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { /** * Object proxy:代理对象 req + 替换敏感词汇的buff * Method method:代理对象中的方法的对象 * Object[] args :代理对象中的方法对象的参数 */ //获取代理对象中方法对象的名称 String name = method.getName(); //判断该方法是否为getParameter方法 if ("getParameter".equals(name)) { //获取req对象中名字叫getParameter的方法返回值 String value = (String) method.invoke(req, args);//替换前调用 //判断value是否为null if (value != null && value.length() > 0) { //遍历集合 for (String ci : list) { //将value中的敏感词进行全部替换 value = value.replaceAll(ci,"***"); return value;//将替换后的内容返回给了代理对象,存在于请求行中 } } } //敏感词汇替换之后再调用一次method.invoke(req,args) return method.invoke(req,args); } } ); //最后放行增强之后的proxy_req chain.doFilter(proxy_req, resp); } public void init(FilterConfig config) throws ServletException { try { //1.获取servletContext对象 ServletContext context = config.getServletContext(); //2.通过context对象获取src下面的 敏感词汇.txt文件 的资源路径 String realPath = context.getRealPath("/WEB-INF/classes/敏感词汇.txt"); //3.通过路径创建字符流对象 BufferedReader br = new BufferedReader(new FileReader(realPath)); //循环读 String line; while ((line = br.readLine()) != null) { list.add(line); } System.out.println(list); br.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } ```
Listener:监听器
概念:web的三大组件之一。
事件监听机制
事件 :一件事情
事件源 :事件发生的地方
监听器 :一个对象
注册监听:将事件、事件源、监听器绑定在一起。 当事件源上发生某个事件后,执行监听器代码
ServletContextListener:监听ServletContext对象的创建和销毁
方法:
void contextDestroyed(ServletContextEvent sce) :ServletContext对象被销毁之前会调用该方法
void contextInitialized(ServletContextEvent sce) :ServletContext对象创建后会调用该方法
步骤:
定义一个类,实现ServletContextListener接口
复写方法
配置
web.xml <listener> <listener-class>cn.itcast.web.listener.ContextLoaderListener</listener-class> </listener>
指定初始化参数<context-param>
注解:
@WebListener
监听器:
package cn.itcast.web.listener; import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.annotation.WebListener; import java.io.FileInputStream; @WebListener public class ContextLoaderListener implements ServletContextListener { /** * 监听ServletContext对象创建的。ServletContext对象服务器启动后自动创建。 * * 在服务器启动后自动调用 * @param servletContextEvent */ @Override public void contextInitialized(ServletContextEvent servletContextEvent) { //加载资源文件 //1.获取ServletContext对象 ServletContext servletContext = servletContextEvent.getServletContext(); //2.加载资源文件 String contextConfigLocation = servletContext.getInitParameter("contextConfigLocation"); //3.获取真实路径 String realPath = servletContext.getRealPath(contextConfigLocation); //4.加载进内存 try{ FileInputStream fis = new FileInputStream(realPath); System.out.println(fis); }catch (Exception e){ e.printStackTrace(); } System.out.println("ServletContext对象被创建了。。。"); } /** * 在服务器关闭后,ServletContext对象被销毁。当服务器正常关闭后该方法被调用 * @param servletContextEvent */ @Override public void contextDestroyed(ServletContextEvent servletContextEvent) { System.out.println("ServletContext对象被销毁了。。。"); } }
AJAX:
概念:
ASynchronous JavaScript And XML 异步的JavaScript 和 XML
异步和同步:客户端和服务器端相互通信的基础上
同步:客户端必须等待服务器端的响应。在等待的期间客户端不能做其他操作。
异步:客户端不需要等待服务器端的响应。在服务器处理请求的过程中,客户端可以进行其他的操作。
Ajax 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。 [1] 通过在后台与服务器进行少量数据交换,Ajax 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。 传统的网页(不使用 Ajax)如果需要更新内容,必须重载整个网页页面。
提升用户的体验
实现方式:
2. JQeury实现方式 1. $.ajax() * 语法:$.ajax({键值对}); //使用$.ajax()发送异步请求 $.ajax({ url:"ajaxServlet1111" , // 请求路径 type:"POST" , //请求方式 //data: "username=jack&age=23",//请求参数 data:{"username":"jack","age":23}, success:function (data) { alert(data); },//响应成功后的回调函数 error:function () { alert("出错啦...") },//表示如果请求响应出现错误,会执行的回调函数 dataType:"text"//设置接受到的响应数据的格式 }); 2. $.get():发送get请求 3. $.post():发送post请求==同理== * 语法:$.get(url, [data], [callback], [type]) $.get( "ajaxServlet1111" , // 请求路径 {"username":"jack","age":23}, function (data) { alert(data); },//响应成功后的回调函数 "json"//设置接受到的响应数据的格式 ); * 参数: * url:请求路径 * data:请求参数 * callback:回调函数 * type:响应结果的类型
只了解:
1. 原生的JS实现方式(了解) //1.创建核心对象 var xmlhttp; if (window.XMLHttpRequest) {// code for IE7+, Firefox, Chrome, Opera, Safari xmlhttp=new XMLHttpRequest(); } else {// code for IE6, IE5 xmlhttp=new ActiveXObject("Microsoft.XMLHTTP"); } //2. 建立连接 /* 参数: 1. 请求方式:GET、POST * get方式,请求参数在URL后边拼接。send方法为空参 * post方式,请求参数在send方法中定义 2. 请求的URL: 3. 同步或异步请求:true(异步)或 false(同步) */ xmlhttp.open("GET","ajaxServlet?username=tom",true); //3.发送请求 //4.接受并处理来自服务器的响应结果 //获取方式 :xmlhttp.responseText //什么时候获取?当服务器响应成功后再获取 //当xmlhttp对象的就绪状态改变时,触发事件onreadystatechange。 xmlhttp.onreadystatechange=function() { //判断readyState就绪状态是否为4,判断status响应状态码是否为200 if (xmlhttp.readyState==4 && xmlhttp.status==200) { //获取服务器的响应结果 var responseText = xmlhttp.responseText; alert(responseText); } }
JSON:
1. 概念:
JavaScript Object Notation JavaScript对象表示法 Person p = new Person(); p.setName("张三"); p.setAge(23); p.setGender("男");
var p = {"name":"张三","age":23,"gender":"男"};
json现在多用于存储和交换文本信息的语法
进行数据的传输
JSON 比 XML 更小、更快,更易解析。
2. 语法:
基本规则
数据在名称/值对中:json数据是由键值对构成的
键用引号(单双都行)引起来,也可以不使用引号
值得取值类型:
数字(整数或浮点数)
字符串(在双引号中)
逻辑值(true 或 false)
数组(在方括号中) {"persons":[{"name":"ll"},{"age":18}]}
对象(在花括号中) {"address":{"province":"陕西"....}}
null
数据由逗号分隔:多个键值对由逗号分隔
花括号保存对象:使用{}定义json 格式
方括号保存数组:[]
获取数据:
json对象.键名
json对象["键名"]
数组对象[索引]
遍历 //1.定义基本格式 var person = {"name": "张三", age: 23, 'gender': true};
var ps = [{"name": "张三", "age": 23, "gender": true}, {"name": "李四", "age": 24, "gender": true}, {"name": "王五", "age": 25, "gender": false}];
//获取ps中的所有值 for (var i = 0; i < ps.length; i++) { var p = ps[i]; for(var key in p){ alert(key+":"+p[key]); } }
3. JSON<==>Java
JSON解析器: * 常见的解析器:Jsonlib,Gson,fastjson,jackson
1. JSON转为Java对象 1. **导入jackson的相关jar包** 2. 创建Jackson核心对象 **ObjectMapper** 3. 调用ObjectMapper的相关方法进行转换 1. **readValue**(json字符串数据,Class) 2. Java对象转换JSON 1. 使用步骤: 1. 导入jackson的相关jar包 2. 创建Jackson核心对象 **ObjectMapper** 3. 调用ObjectMapper的相关方法进行转换 1. 转换方法: * **writeValue**(参数1,obj): 参数1: File:将obj对象转换为JSON字符串,并保存到指定的文件中 Writer:将obj对象转换为JSON字符串,并将json数据填充到字符输出流中 OutputStream:将obj对象转换为JSON字符串,并将json数据填充到字节输出流中 * **writeValueAsString**(obj):将对象转为json字符串 2. 注解: 1. @JsonIgnore:排除属性。 2. @**JsonFormat**:属性值得格式化 * @JsonFormat(pattern = "yyyy-MM-dd") 3. 复杂java对象转换 1. List:数组 2. Map:对象格式一致
案例:
* 校验用户名是否存在 1. 服务器响应的数据,在客户端使用时,要想当做json数据格式使用。有两种解决方案: 1. $.get(type):将最后一个参数type指定为"json" 2. 在服务器端设置MIME类型 response.setContentType("application/json;charset=utf-8");