客户端通过网络协议(如Http),请求进入服务器,
WebSeervice收到请求,其中的**WebServerPlugin(服务插件)**判断要访问的文件是静态还是动态的.
静态直接找到资源文件(FIle System),动态的经过jsp,servlet(web技术)增强后(比如用jdbc连接数据库),
再通过WebServer(Web服务)找到对应的资源文件,然后以一种编码格式,响应回给客户端.
http使用80端口;https使用443端口,s指的是SSL/TLS协议,在HTTP和TCP/IP协议中间
http2.0=http/1.1版本,允许客户端与服务器连接后,获得多个资源.1.0是只能获取一个资源
消息头(请求头):告诉服务器怎样响应你这个请求
Accept: */* 你这个请求的数据类型
Accept-Encoding: gzip, deflate, br 编码格式
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6 语言环境
cache-control: max-age=0 缓存控制,最大缓存存活时间
Connection: keep-alive 连接成功后的持久策略,keep-alive始终保持连接
Host: www.dealctr.com 主机信息
reFresh :告诉客户端,多久刷新一次
location :网页是否重新定位
200:请求响应成功
300:请求重定向
404:找不到资源
500:服务器代码错误.502:网关错误
思考:浏览器从输入网址回车,到页面展示回来,经历了什么
服务器是一种被动的操作,处理请求与给用户回复响应
微软windows自带IIS服务器.
Tomcat是一款先进,稳定,免费的轻量级应用服务器
重新部署项目是重新加载当前一个项目.
java的根加载器在r(runtiem)t.jar包里.
启动startup.bat后,Tomcat的默认网址是http://localhost:8000/
conf下的server.xml文件是tomcat的配置文件,可以在里面修改初始参数,如端口号
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
改变本机ip地址访问前缀:修改C:\Windows\System32\drivers\etc\hosts中的127.0.0.1(本地ip地址)的映射网址.
# 设置本机的ip地址中的,127.0.0.1和LiChangGe127.0.0.1的,映射域名为activate.navicat.com
127.0.0.1 LiChangGe127.0.0.1 activate.navicat.com
127.0.0.1 LiChangGe
# 都可以用
http://activate.navicat.com:8080/
http://lichangge:8080/
如果不可以,就再修改server.xml的host属性
<Host name="LiChangGe" appBase="webapps" unpackWARs="true" autoDeploy="true">Host>
一个常见的TomcatWeb项目基本结构如下:webapps(项目顶级目录)\ROOT(自己的web项目)+index.jsp\WEB-INFO(web程序配置信息目录)\web.xml(web程序配置文件)
Tomcat的examples是官方API包
# 查看maven版本
C:\Users\林木>mvn -version
Apache Maven 3.8.3 (ff8e977a158738155dc465c6a97ffaf31982d739)
# 环境变量配置,你自己的maven安装目录
MAVEN_HOME
D:\Maven\apache-maven-3.8.3
# maven的运行程序bin目录,用idea可以不配置
M2_HOME
D:\Maven\apache-maven-3.8.3\bin
# Path引用maven,必须有
Path
%MAVEN_HOME%\bin
conf\settings.xml配置maven本地仓库目录和镜像
# 本地仓库,配置后去看看C:\用户\李长歌(这里是你自己的电脑账户)\.m2(默认隐藏的),这是maven默认的本地仓库,可以删掉.
<localRepository>D:\Maven\apache-maven-3.8.3\mvn_propertieslocalRepository>
# 镜像
<mirrors>
<mirror>
<id>aliyunmavenid>
<mirrorOf>*mirrorOf>
<name>Nexus aliyunname>
<url>https://maven.aliyun.com/repository/publicurl>
mirror>
mirrors>
一键直达
用模板创建
maven常用的全局设置
添加webapp目录
一个标准的web子模块
http://localhost:8080/xiaomi
父类和子类模块的maven代码会联动
<groupId>com.changGe.ligroupId>
<artifactId>JavaWebartifactId>
<version>1.0-SNAPSHOTversion>
<modules>
<module>XiaoMimodule>
modules>
<name>JavaWebname>
<packaging>pompackaging>
# 子类
<groupId>com.changGe.ligroupId>
<artifactId>XiaoMiartifactId>
<version>1.0-SNAPSHOTversion>
<packaging>warpackaging>
<name>XiaoMi Maven Webappname>
配置运行时的java版本信息
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<maven.compiler.source>1.8maven.compiler.source>
<maven.compiler.target>1.8maven.compiler.target>
properties>
配置依赖
<dependencies>
dependencies>
需要导包
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>4.0.1version>
<scope>providedscope>
dependency>
当存储数据时,其下所有类本质是一个Map集合
继承HttpServlet(javax.servlet.http包下),需要Maven导入依赖
只要是实现了Servlet接口,就叫做Servlet小程序
<dependency>
<groupId>javax.servletgroupId>
<artifactId>servlet-apiartifactId>
<version>2.5version>
dependency>
重写方法
package com.changGe.li.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class TestServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setCharacterEncoding("utf-8");
resp.getWriter().print("Hello World");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
配置域名映射
<servlet>
<servlet-name>heservlet-name>
<servlet-class>com.changGe.li.servlet.TestServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>heservlet-name>
<url-pattern>/heurl-pattern>
servlet-mapping>
tomcat日志文件配置
浏览器向服务器发送请求,访问的是web容器(可以理解为服务器)
浏览器访问的是映射,然后返回IP地址
客户端发送请求,到达web容器.
如果是第一次的话,web容器直接访问servlet,第二次和以后,就是带着请求,找servlet的对应的service方法(如doGet()和doPost()等).
同时web容器的respons对象,也会监听接收,来自serivice的响应.监听到数据,web容器响应给客户端
表单提交时携带请求和请求参数
<servlet>
<servlet-name>modifyPasswordservlet-name>
<servlet-class>com.changGe.li.servlets.ModifyPasswordServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>modifyPasswordservlet-name>
<url-pattern>/jsp/user.dourl-pattern>
servlet-mapping>
<url-pattern>/*.dourl-pattern>
<a href="${pageContext.request.contextPath}/hello">
<url-pattern>/hellourl-pattern>
<url-pattern>/hello.dourl-pattern>
调用对应的service(),如上面的表单提交方式是get,就找到doGet();
执行其中的实现代码
public class ModifyPasswordServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//重定向发送一个请求且携带参数
resp.sendRedirect(req.getContextPath()+"/jsp/user.do?method=query");
}
每个程序都有一个对应的上下文对象(ServletContext)
实现Servlet间共享数据
<servlet>
<servlet-name>heservlet-name>
<servlet-class>com.changGe.li.servlet.TestServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>heservlet-name>
<url-pattern>/hellourl-pattern>
servlet-mapping>
<servlet>
<servlet-name>helloservlet-name>
<servlet-class>com.changGe.li.servlet.TestServletOneservlet-class>
servlet>
<servlet-mapping>
<servlet-name>helloservlet-name>
<url-pattern>/hello.dourl-pattern>
servlet-mapping>
public class TestServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setCharacterEncoding("utf-8");
ServletContext servletContext = this.getServletContext();
servletContext.setAttribute("name","武则天");
}
}
public class TestServletOne extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setCharacterEncoding("utf-8");
ServletContext servletContext = this.getServletContext();
Object name = servletContext.getAttribute("name");
System.out.println(name);
}
}
servletContext转发
// 一定要写上/代表当前web项目目录下
servletContext.getRequestDispatcher("/info.jsp").forward(req,resp);
<context-param>
<param-name>nameparam-name>
<param-value>李长歌param-value>
context-param>
ServletContext servletContext = this.getServletContext();
String name = servletContext.getInitParameter("name");
System.out.println(name);//李长歌
classes俗称类路径
如果java目录下的资源没有导入成功,在pom.xml中添加下列代码
然后删除target目录,重新部署或重启tomcat服务器
filtering的作用 (4条消息) maven Filtering true 作用_滕青山YYDS的博客-CSDN博客
<build>
<resources>
<resource>
<directory>src/main/javadirectory>
<includes>
<include>**/*.propertiesinclude>
<include>**/*.xmlinclude>
includes>
<filtering>truefiltering>
resource>
resources>
build>
读取资源文件
public class TestServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setCharacterEncoding("utf-8");
ServletContext servletContext = this.getServletContext();
InputStream resourceAsStream = servletContext.getResourceAsStream("/WEB-INF/classes/com/changGe/li/lib/test1.properties");
Properties properties = new Properties();
properties.load(resourceAsStream);
String name = properties.getProperty("name");
System.out.println(name);
}
}
服务器接收到浏览器的请求后,针对这个请求自动创建Request(请求)和Respons(响应)对象
HttpServlet源码中有初始的状态码
public interface HttpServletRequest extends ServletRequest {
/**
* String identifier for Basic authentication. Value "BASIC"
*/
public static final String BASIC_AUTH = "BASIC";
/**
* String identifier for Form authentication. Value "FORM"
*/
public static final String FORM_AUTH = "FORM";
/**
* String identifier for Client Certificate authentication. Value "CLIENT_CERT"
*/
public static final String CLIENT_CERT_AUTH = "CLIENT_CERT";
请求转发时,可以携带参数
req.setAttribute("name","李长歌");
req.getRequestDispatcher("info.jsp").forward(req,resp);
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取所有的值,返回数组
String[] names = req.getParameterValues("check");
for (String name : names) {
System.out.println(name);
}
}
//req.getContextPath() = 当前项目目录路径:localhost:8080
resp.sendRedirect(req.getContextPath()+"/info.jsp");
重写向时不会传递参数
响应数据
//把集合响应回去,ajax用做函数的data
resp.setContentType("application/json");
resp.setCharacterEncoding("utf-8");
try {
PrintWriter writer = resp.getWriter();
//将集合变成json对象输出
writer.write(JSON.toJSONString(result));
writer.flush();
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
下载文件:respons负责把读取到的数据,响应回给浏览器
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//以utf-8解析请求
resp.setCharacterEncoding("utf-8");
//让浏览器以utf-8模式解析响应
resp.setHeader("Content-type", "text/html;charset=UTF-8");
String imgUrl = "E:\\JAVA\\JavaWeb\\XiaoMi\\src\\main\\resources\\test.properties";
//从最后一个/开始截取,获得文件名
String fileName = imgUrl.substring(imgUrl.lastIndexOf("\\") + 1);
//输入流
FileInputStream fileInputStream = new FileInputStream(imgUrl); //设置响应头:内容类型,附件;文件名字=
resp.setHeader("Content-Disposition","attachment;filename="+ URLEncoder.encode(fileName,"utf-8"));
//获取响应的文件输出流
ServletOutputStream outputStream = resp.getOutputStream();
byte[] bytes = new byte[10];
int length = 0;
while ((length = fileInputStream.read(bytes)) != -1){
outputStream.write(bytes,0,length);
}
}
resp.setCharacterEncoding("utf-8");
resp.setHeader("Content-type", "text/html;charset=UTF-8");
String imgUrl = "E:\\JAVA\\JavaWeb\\XiaoMi\\src\\main\\resources\\test.properties";
//从最后一个/开始截取,获得文件名
String fileName = imgUrl.substring(imgUrl.lastIndexOf("\\") + 1);
//输入流
FileInputStream fileInputStream = new FileInputStream(imgUrl);
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
FileReader fileReader = new FileReader(imgUrl);
//设置响应头:内容类型,附件;文件名字=
resp.setHeader("Content-Disposition","attachment;filename="+ URLEncoder.encode(fileName,"utf-8"));
//获取响应的文件输出流
ServletOutputStream outputStream = resp.getOutputStream();
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream);
// PrintWriter writer = resp.getWriter();
byte[] bytes = new byte[10];
char[] chars = new char[1024];
int length = 0;
/*
while ((length = fileInputStream.read(bytes)) != -1){
outputStream.write(bytes,0,length);
}*/
while ((length = bufferedInputStream.read(bytes)) != -1){
bufferedOutputStream.write(bytes,0,length);
bufferedOutputStream.flush();
}
bufferedInputStream.close();
bufferedOutputStream.close();
outputStream.close();
fileInputStream.close();
验证码
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//宽高,以8位RGB色彩模式打包出去
BufferedImage bufferedImage = new BufferedImage(300,300,BufferedImage.TYPE_INT_RGB);
//得到支笔
Graphics2D graphics = (Graphics2D) bufferedImage.getGraphics();
graphics.setBackground(new Color(0xEBA9E7));
graphics.setColor(new Color(0x00F4E0));
//实心矩形,x,y,width,height
graphics.fillRect(400,400,600,600);
//字体,罗马基线,大小
graphics.setFont(new Font("方正舒体",Font.ROMAN_BASELINE,50));
//要写的字符串,x,y
graphics.drawString(verifyCode(),50,200);
//让浏览器以图片格式解析
resp.setContentType("image/png");
//设置浏览器的3秒刷新一次
resp.setHeader("refresh","3");
//多少秒后过期
resp.setDateHeader("expires",-1);
//缓存控制不缓存
resp.setHeader("Cache-Control","no-cache");
//程序不缓存,作用和上面一样,一般两者一起使用
resp.setHeader("Program","no-cache");
//把图片,按照格式,写到一个地方去
ImageIO.write(bufferedImage,"png",resp.getOutputStream());
}
public String verifyCode(){
Random random = new Random();
/**
* valueOf()的底层:return (obj == null) ? "null" : obj.toString();
* 它不会报空指针异常,但是如果是null,也会直接变成"null"
*/
String number = String.valueOf(random.nextInt(10000000));
StringBuilder stringBuilder = new StringBuilder(number);
//保证验证码是7个字符
for (int i = 0; i < 7 - number.length(); i++) {
stringBuilder.append("x");
}
System.out.println(stringBuilder);
return stringBuilder.toString();
}
2、请求转发
使用request.getRequestDispatcher(“xx.jsp”).forward(request,response)请求转发。forward(request,response)用于保存内置对象request和response。是服务器的行为:服务器会代替客户端去访问转发页面,从本质是一次请求,转发后请求对象会保存,地址栏的URL地址不会改变。
有状态会话:会话(客户端和服务器间的一次交流seesion) + 缓存(cookie)
本质是把用户的数据写给浏览器,由浏览器保存
用cookie读取上一次访问时间:刷新一次数据也刷新
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String format = new SimpleDateFormat("yyyy年MM月dd日:HH时mm分ss秒").format(new Date());
Cookie lastTime = new Cookie("lastTime", format);
boolean flag = true;
Cookie[] cookies = req.getCookies();
if(cookies != null && cookies.length > 0){
for (Cookie cookie : cookies) {
String value = cookie.getName();
if(value != null && value.equals("lastTime")){
flag = false;
//特定格式解析字符串,常用于中文解码
req.setAttribute("lastTime", URLDecoder.decode(cookie.getValue(),"utf-8"));
//更新登录时间
cookie.setValue(format);
/**
* 缓存时间0秒,就是删除cookie,
* 只有用户关闭浏览器才会删除cookie
*/
cookie.setMaxAge(60 * 60);//单位是秒
resp.addCookie(lastTime);
req.getRequestDispatcher("index.jsp").forward(req,resp);
return;
}
}//for
}
if(flag){
resp.addCookie(lastTime);
req.setAttribute("msg", "这是您第一次登录");
req.getRequestDispatcher("info.jsp").forward(req,resp);
}
}
精简版
String format = new SimpleDateFormat("yyyy年MM月dd日:HH时mm分ss秒").format(new Date());
Cookie[] cookies = req.getCookies();
boolean flag = true;
if(cookies != null && cookies.length > 0){
for (Cookie cookie : cookies) {
String value = cookie.getName();
if(value != null && value.equals("lastTime")){
flag = false;
req.setAttribute("msg", "您上一次登录时间:"+URLDecoder.decode(cookie.getValue(),"utf-8"));
}
}//for
}
if(flag){
req.setAttribute("msg", "这是您第一次登录");
}
Cookie lastTime = new Cookie("lastTime", format);
resp.addCookie(lastTime);
req.getRequestDispatcher("info.jsp").forward(req,resp);
浏览器的applition里可以看到cookie缓存.,可以删除掉特定的cookie
只有清除了localhost:8080的缓存后,cookie才真正消失,每次浏览器都默认存储了一些cookie
用everything我们可以找到**cookiie的存放位置,**只是我们不能用(没有权限,到AC就看不到了)
浏览器最多发送300个coolie,约是15个网站的,最大共1200kb数据.
服务器会为每个浏览器都创建一个seesion,在服务器上保存用户的数据,全局作用域,直到浏览器关闭.
seesion在浏览器默认存储30分钟
<session-config>
<session-timeout>15session-timeout>
session-config>
seesion存储在cookie中,去浏览器的applition中找到cookie看,或者请求头的cookie里保存的有
底层代码相当于response.addcookie(new Cookie(“JSSSIONID”,value));
//约等于此,不过是服务器内部实现的,我们这样的不行
resp.addCookie(new Cookie("JSSSIONID", "123"));
seesion可以存储对象,能用seesion就不要用context
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpSession session = req.getSession();
session.setAttribute("name","李长歌");
session.setAttribute("age","18");
session.setAttribute("sex","女");
//如果是新创建的
if(session.isNew()){
Enumeration<String> attributeNames = session.getAttributeNames();
//sessionId是D6E8AD19A02583A4CB3DA5F36F86EB28
System.out.println("sessionId是"+session.getId());
/**
* 结果:
* 女
* 李长歌
* 18
*
* 页面自动回到浏览器主页了,因为session注销了
*/
while (attributeNames.hasMoreElements()){
String name = attributeNames.nextElement();
System.out.println(session.getAttribute(name));
//可以用于用户退出时删除用户信息
session.removeAttribute(name);
}
//注销
session.invalidate();
}
}
和全文索引的应用场景一样
服务器访问任何资源,本质是访问Servlet. 因为idea的tomcat>work目录下的jsp页面最后变成了.java文件.
JSP源码分析__板蓝根_的博客-CSDN博客_jsp源码
这个博客没有找到,就在这里面找
这是我最终找到的路径:C:\Users\林木\AppData\Local\JetBrains\IntelliJIdea2021.2\tomcat\61c407dd-c490-4564-89ac-71da59dbac6b\work\Catalina\localhost\XiaoMi\org\apache\jsp
继承自HttpJspBase类,HttpJspBase继承自HttpServlet类
public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase
初始化,销毁和服务三大方法
public void _jspInit() {
}
public void _jspDestroy() {
}
public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
判断请求类型.method()
if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method)) {
response.setHeader("Allow","GET, HEAD, POST, OPTIONS");
response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSP 只允许 GET、POST 或 HEAD。Jasper 还允许 OPTIONS");
return;
}
初始化对象有context(改名application),page = this…
final javax.servlet.jsp.PageContext pageContext;
javax.servlet.http.HttpSession session = null;
final javax.servlet.ServletContext application;
final javax.servlet.ServletConfig config;
javax.servlet.jsp.JspWriter out = null;
final java.lang.Object page = this;
javax.servlet.jsp.JspWriter _jspx_out = null;
javax.servlet.jsp.PageContext _jspx_page_context = null;
有个try里面,在输出页面前为一些默认的对象,如pageContext等赋值,我们可以在jsp页面中直接使用
try {
response.setContentType("text/html;charset=utf-8");
pageContext = _jspxFactory.getPageContext(this, request, response,
null, true, 8192, true);
_jspx_page_context = pageContext;
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
_jspx_out = out;
out.write("\n");
out.write("\n");
out.write("\n");
out.write("\n");
<%--这是jsp表达式,加"="号专门用来输出--%>
<input type="text" value="名字是:<% String name="李长歌"; %>
<%= name%>"/>
<!--对应到jsp.java底层->
out.write("
javax-servlet-jsp-api依赖
<dependency>
<groupId>javax.servlet.jspgroupId>
<artifactId>jsp-apiartifactId>
<version>2.0version>
dependency>
html的注释可以在控制台看到,jsp不显示
<%--jsp脚本在_jspService()中--%>
<% for(int i = 0 ; i < 5; i++){%>
hello world<%= i %>
<% } %>
<%--jsp声明在jsp类中--%>
<%!
public void test(){}
%>
自定义错误页面
<%@ page pageEncoding="utf-8" %>
<%--jsp标签:写在页面最上面,作为配置.显式声明这是一个错误页面--%>
<%@ page isErrorPage="true" %>
<%@page errorPage="info.jsp" %>
<html>
<body>
<% int i = 1 / 0;%>
body>
html>
或
<error-page>
<error-code>500error-code>
<location>/info.jsplocation>
error-page>
添加公共页面
<%--是将页面中的代码提出来,然后和现有页面代码拼接在一起--%>
<%@ include file="info.jsp" %>
out.write("\r\n");
out.write(" Info \r\n");
out.write("\r\n");
out.write("\r\n");
out.write("\r\n");
out.write("info下的h3
\r\n");
out.write(" \r\n");
out.write("\r\n");
out.write("\r\n");
out.write("\r\n");
out.write("\r\n");
out.write("\n");
out.write("\n");
out.write("\n");
out.write("\n");
<%--第二种方法--%>
<%--这是调用其它页面,不会出现代码冲突的问题--%>
out.write(" 22222
\n");
org.apache.jasper.runtime.JspRuntimeLibrary.include(request, response, "info.jsp", out, false);
out.write("\n");
<%--作用域是request--%>
name is:${pageContext.request.getParameter("name")}
static包下一般放前端的资源,如css,img,js和plugins等.
WEB-INF目录对用户不可见
作用域优先级:pageScope > requestScope > sessionScope > pageContext(页面运行时)>applicationScope(服务器)
如果没有给定取值作用域,则默认从pageScope开始查找,找到则返回,没找到则按照上述顺序继续查找,以此类推,知道找到为止。
如果最终没有找到,则返回null。
<%
pageContext.setAttribute("name","李长歌");
session.setAttribute("name1","session");
request.setAttribute("name2","request");
application.setAttribute("name3","application");
//获取值
String name5 = (String) pageContext.findAttribute("name5");
%>
<%--找不到也不报错,el表达式自动过滤null值,不显示在页面中--%>
name:${name}
name1:${name1}
name2:${name2}
name3:${name3}
name5:${name5}
设置作用域
<%
//等同于session.setAttribute("key","value");
pageContext.setAttribute("key","value",pageContext.SESSION_SCOPE);
%>
作用域保存数据的重要性从低到高:request(客户端看完即删,新闻图片等.) < seestion(需要二次使用,但不事关关键业务,如购物车) < application(需要全局作用,事关关键业务,如聊天数据)
<%
pagecontext.setAttribute("name","李长歌");
request = pagecontex.getRequest();
requext.forward("forward.jsp");
%>
<%--页面转发时,会自动将数据也给转发走--%>
<%--info页面下--%>
<%
String name = (String)pagecontext.getAttribute("name");
out.print(name);
%>
jstl-api依赖和standrard标签库依赖
如果报错说找不到这个包,可能是因为tomcat中没有这个jar包,直接粘到tomcat的work目录中去
<dependency>
<groupId>jstlgroupId>
<artifactId>jstlartifactId>
<version>1.2version>
dependency>
<dependency>
<groupId>taglibsgroupId>
<artifactId>standardartifactId>
<version>1.1.2version>
dependency>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--写在最顶上,导入core标签库,字首(也就是前缀)为c,字首可以随便写--%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%--如果报错:根据标记文件中的TLD或attribute指令,attribute[items]不接受任何表达式
是因为和tomcat中的jstl-api.jar包不兼容
就换成下面这个--%>
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core_rt" %>
switch循环和if判断
<%--定义变量sorce,赋值为100--%>
<%-- 把test判断的值,赋值给number --%>
<%--循环判断--%>
<%--会自动break--%>
增加for
<%
ArrayList
jsp:useBean的用法_远方©的博客-CSDN博客_jsp:usebean
<%--实例化对象User--%>
<%--获取表单中的所有值,并一一赋值给User类,对应的set方法--%>
<%--从user对象中取值--%>
<%--李长歌--%>
<%--18--%>
<%=user.getAge()%><%--18--%>
<form action="index.jsp" method="get">
<input type="text" name="name" value="李长歌">
<input type="text" name="age" value="18">
<input type="submit" value="请提交">
form>
<%--实例化对象User--%>
<jsp:useBean id="user" class="com.changGe.li.User" scope="page"/>
<%--只给setName()赋值--%>
<jsp:setProperty name="user" property="name"/>
<jsp:getProperty name="user" property="name"/><%--李长歌--%>
<%--尽管age的input输入了值,还是为0--%>
<jsp:getProperty name="user" property="age"/><%--0--%>
<%=user.getAge()%><%--0--%>
<form action="index.jsp" method="get">
<input type="text" name="name" value="李长歌">
<input type="text" name="age" value="18">
<input type="submit" value="请提交">
form>
<%--实例化对象User--%>
<jsp:useBean id="user" class="com.changGe.li.User" scope="page"/>
<%--给setName()赋值"武则天"--%>
<jsp:setProperty name="user" property="name" value="武则天"/>
<%--最后得到的还是"武则天"--%>
<jsp:getProperty name="user" property="name"/>
<form action="index.jsp?name=李世民" method="get">
<input type="text" name="name" value="李长歌">
<input type="text" name="age" value="18">
<input type="submit" value="请提交">
form>
<%--实例化对象User--%>
<jsp:useBean id="user" class="com.changGe.li.User" scope="page"/>
<%--从请求的参数取值name,赋值给user对象的setName--%>
<jsp:setProperty name="user" property="name" param="name"/>
<%--最后得到的还是"李长歌"--%>
<jsp:getProperty name="user" property="name"/>
<body>
<%--实例化对象User--%>
<jsp:useBean id="user" class="com.changGe.li.User" scope="page"/>
<%--赋值给user对象的setName--%>
<jsp:setProperty name="user" property="name" value="武则天"/>
<%--"武则天"--%>
<jsp:getProperty name="user" property="name"/>
body>
三层架构就是在Model层进行dao(数据持久),service(业务处理)的中间过渡
mysql-connector-java依赖,一定要用和自己数据库版本一样的jar包(依赖),不同版本的结构不同
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.27version>
dependency>
实现Filter下的方法init初始化,doFIlter业务,destroy销毁,可以只实现doFilter()
@Override
public void init(FilterConfig filterConfig) throws ServletException {
Filter.super.init(filterConfig);
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
}
@Override
public void destroy() {
Filter.super.destroy();
}
欢迎登录
<servlet>
<servlet-name>loginservlet-name>
<servlet-class>com.changGe.li.servlets.LoginServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>loginservlet-name>
<url-pattern>/loginurl-pattern>
servlet-mapping>
成功了就跳转主页,失败是失败页面.
public class LoginServlet extends HttpServlet {
//数据库工具类
private UserService userService = new UserServiceImpl();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String userCode = req.getParameter("userCode");
String password = req.getParameter("password");
//根据用户名和密码找到User对象
User user = userService.getUser(userCode,password);
//不为空就保存到session中
if(user != null){
req.getSession().setAttribute("user",user);
resp.sendRedirect(req.getContextPath()+"/jsp/frame.jsp");
}else {
//失败就重定向
req.setAttribute("error","用户名或密码错误");
req.getRequestDispatcher("login.jsp").forward(req,resp);
}
}
}
注销后回到登录页面.
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
User user = (User)req.getSession().getAttribute("user");
if(user != null){
req.getSession().removeAttribute("user");
resp.sendRedirect(req.getContextPath()+"/login.jsp");
}else {
//为空,代表已经被删除了
req.getRequestDispatcher("error.jsp").forward(req,resp);
}
}
<filter>
<filter-name>forcoLoginfilter-name>
<filter-class>com.changGe.li.filters.ForcoLoginFilterfilter-class>
filter>
<filter-mapping>
<filter-name>forcoLoginfilter-name>
<url-pattern>/jsp/*url-pattern>
filter-mapping>
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resq = (HttpServletResponse) response;
//从session中获取user对象
User user = (User)req.getSession().getAttribute("user");
if(user == null){
request.setAttribute("error","请先登录,谢谢");
resq.sendRedirect(req.getContextPath()+"/login.jsp?error="+ URLEncoder.encode("请先登录,谢谢","utf-8"));
}else{
//找到之后直接进入主页.不用登录
//必须让请求和响应 链接 起来后,程序才会继续进行,不然就卡住
chain.doFilter(req, resq);
}
}
public static final String USER_SEESION = "user";
用这个思想,实现一个判断用户vip等级的demo.
主要是过滤器根据username获取到的seesion,进而获取对象,然后判断等级
info.jsp
您的等级是:${grade}
web.xml
<filter>
<filter-name>verifyfilter-name>
<filter-class>com.changGe.li.FilterTestfilter-class>
filter>
<filter-mapping>
<filter-name>verifyfilter-name>
<servlet-name>heservlet-name>
<url-pattern>/*url-pattern>
filter-mapping>
<servlet>
<servlet-name>heservlet-name>
<servlet-class>com.changGe.li.servlet.TestServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>heservlet-name>
<url-pattern>/hellourl-pattern>
servlet-mapping>
TestServlet
public class TestServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String grade = req.getParameter("grade");
req.getSession().setAttribute("grade",grade);
req.getRequestDispatcher("info.jsp").forward(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
FilterTest
public class FilterTest implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resq = (HttpServletResponse) response;
String grade = req.getParameter("grade");
if(grade == null || grade.equals("")){
//从session中获取user对象
grade = String.valueOf(req.getSession().getAttribute("grade"));
}
if(grade != null && !grade.equals("")){
System.out.println("if中的"+grade);
switch (grade){
case "1":
req.setAttribute("grade","1");
break;
case "2":
req.setAttribute("grade","2");
break;
default:
req.setAttribute("grade","3");
}
chain.doFilter(req, resq);
}else{
resq.getWriter().write("等级为空");
}
}
}
各种类型的监听器都可以实现,如HttpSestionListener,始终监听session域
index.jsp
<form action="hello" method="get">
<input type="submit" value="提交">
form>
<listener>
<listener-class>com.changGe.li.ListenerTestlistener-class>
listener>
监听到有session被创建时,就创建一个sess的session,赋值
有session被销毁时,得到资源
public class ListenerTest implements HttpSessionListener {
//有session被创建时
@Override
public void sessionCreated(HttpSessionEvent se) {
//创建session
se.getSession().setAttribute("sess", URLEncoder.encode("监听到session被创建了"));
}
//有session被销毁时
@Override
public void sessionDestroyed(HttpSessionEvent se) {
Object source = se.getSource();
//输出结果org.apache.catalina.session.StandardSessionFacade@8539a6f
System.out.println("监听到的资源是:"+source.toString());
}
}
servlet中先创建一个session,触发sessionCreated()
然后得到sessionCreated()创建的session打印出去
最后删除自己创建的session
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//创建session
req.getSession().setAttribute("name","李长歌");
//写去session
resp.getWriter().write(String.valueOf(req.getSession().getAttribute("sess")));
//删除session
req.getSession().invalidate();
}
只要有个session被创建后,在线人数就+1;销毁时在线人数-1
servlet
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//一秒刷新一次
resp.setHeader("refresh","1");
//一定要从ServletContext中取值,ServletContext监控所有session
String online = String.valueOf(req.getServletContext().getAttribute("online"));
req.setAttribute("online",online);
req.getRequestDispatcher("info.jsp").forward(req,resp);
}
public class ListenerTest implements HttpSessionListener {
//有session被创建时
@Override
public void sessionCreated(HttpSessionEvent se) {
//在最高的作用域servletContext操作session
ServletContext servletContext = se.getSession().getServletContext();
Integer online = (Integer) servletContext.getAttribute("online");
if(online == null || online <= 0){
online = 1;
}else {
online ++;
}
servletContext.setAttribute("online",online);
}
//有session被销毁时
@Override
public void sessionDestroyed(HttpSessionEvent se) {
ServletContext servletContext = se.getSession().getServletContext();
Integer online = (Integer)servletContext.getAttribute("online");
if(online == null || online < 0){
online = 0;
}else {
online --;
}
servletContext.setAttribute("online",online);
}
}
info.jsp
在线人数是:${online}
web.xml
<session-config>
<session-timeout>1session-timeout>
session-config>
public static void main(String[] args) {
JFrame jFrame = new JFrame();
//适配器模式,windowAdapter实现了WindowListener
jFrame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosed(WindowEvent e) {
super.windowClosed(e);
}
});
}
WindowAdapter实现了WindowListener
public abstract class WindowAdapter
implements WindowListener, WindowStateListener, WindowFocusListener
{
juit单元测试依赖
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.13.2version>
<scope>testscope>
dependency>
q.setAttribute(“online”,online);
req.getRequestDispatcher(“info.jsp”).forward(req,resp);
}
```java
public class ListenerTest implements HttpSessionListener {
//有session被创建时
@Override
public void sessionCreated(HttpSessionEvent se) {
//在最高的作用域servletContext操作session
ServletContext servletContext = se.getSession().getServletContext();
Integer online = (Integer) servletContext.getAttribute("online");
if(online == null || online <= 0){
online = 1;
}else {
online ++;
}
servletContext.setAttribute("online",online);
}
//有session被销毁时
@Override
public void sessionDestroyed(HttpSessionEvent se) {
ServletContext servletContext = se.getSession().getServletContext();
Integer online = (Integer)servletContext.getAttribute("online");
if(online == null || online < 0){
online = 0;
}else {
online --;
}
servletContext.setAttribute("online",online);
}
}
info.jsp
在线人数是:${online}
web.xml
<session-config>
<session-timeout>1session-timeout>
session-config>
public static void main(String[] args) {
JFrame jFrame = new JFrame();
//适配器模式,windowAdapter实现了WindowListener
jFrame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosed(WindowEvent e) {
super.windowClosed(e);
}
});
}
WindowAdapter实现了WindowListener
public abstract class WindowAdapter
implements WindowListener, WindowStateListener, WindowFocusListener
{
juit单元测试依赖
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.13.2version>
<scope>testscope>
dependency>
ORM对象关系映射 :就是实体类和数据库字段互相对应