CS: Client Server 客户端和服务器
总结: 两种架构各有优缺点,以后工作都有可能涉及到
服务器实际上就是一台高配置的电脑,通常配置内存8g以上,cpu8核以上,硬盘T级别
web服务器: 电脑上安装了web服务器软件,提供复杂的数据及文件共享功能
邮件服务器: 电脑上安装了邮件服务器,提供了收发邮件的功能
数据库服务器: 电脑上安装了数据库软件(mysql oracle) 提供了数据的增删改查
ftp服务器:电脑上安装了ftp服务软件,提供了文件上传下载功能
import java.io.FileInputStream; import java.io.IOException; import java.io.OutputStream; import java.net.ServerSocket; public class Socket{ public static void main(String[] args)throws IOException { //创建服务器socket,并指定端口号 ServerSocket serverSocket=new ServerSocket(8888); System.out.println("服务器已经启动"); //循环接收新的socket while(true){ //得到链接进来的socket对象 java.net.Socket socket=serverSocket.accept(); //构建数据发送通道 OutputStream outputStream=socket.getOutputStream(); //得到文件的输入流 FileInputStream inputStream=new FileInputStream("/home/chenjiabing/文档/a.html"); //把文件数据读取到,然后写出 int len=0; while((len=inputStream.read())!=-1){ outputStream.write(len); } //关闭流 outputStream.close(); inputStream.close(); } } }
webSphere : 是IBM公司产品,闭源收费
Tomcat: apache的产品,属于开源免费应用在中小型网站中
weblogic : BEA公司的产品 闭源收费
静态资源:任何用户 任何时间访问 内容都一样
动态资源: 不同的用户访问显示的内容可能会不一样,通过计算生成的网页
打包并发布(把servlet添加到tomcat中的webapps目录下)
运行tomact服务器
创建maven项目
创建一个类,继承 HttpServlet
HttpServlet
类,因为这里我们还需要一个jar包,我们在项目上右击选择 properties
,然后选择 Targeted Runtime
选择你自己的Tomcat,ok import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class HelloServletextends HttpServlet{ //这个方法可以处理任何的请求,get.post delete put 并且可以在适当的时候调用处理请求类型的各种方法 @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //设置响应的数据类型 response.setContentType("text/html"); //设置响应编码格式为UTF-8,否则将会出现中文乱码 response.setCharacterEncoding("UTF-8"); //得到输出对象 PrintWriter writer=response.getWriter(); //返回数据,这里是向浏览器中写入数据 writer.write("<h1>Hello World--你好世界</h1>"); //关闭输出流 writer.close(); } }
<servlet> <!-- 自己定义的名字,任意 --> <servlet-name>HelloWorld</servlet-name> <!-- 指定Servlet的全类名 --> <servlet-class>cn.tedu.HelloServlet</servlet-class> </servlet> <!-- 指定Servlet的映射关系 --> <servlet-mapping> <!-- 这个是上面定义的Servlet的名字 --> <servlet-name>HelloWorld</servlet-name> <!-- 指定映射的地址: 这里只需要在浏览器中输入http://localhost:8080/helloWorld即可调用这个Servlet --> <url-pattern>/helloWorld</url-pattern> </servlet-mapping>
http://localhost:8080/helloWorld
浏览器发出请求,会先由浏览器的通讯模块对请求进行打包,打包后把数据传递给tomcat服务器
tomcat由通讯模块接收请求包并且对请求包进行解析,把请求数据封装到Request对象中,并且创建Response对象用于给浏览器返回数据
tomcat通讯模块通过查找web.xml文件和本次请求相对应的Sevlet,通过反射技术创建对象并且调用对象的Service方法
并把Request和Response传递到方法中
在service方法中书写各种业务代码,把需要返回的数据交给Respose对象,由Response对象传递给通讯模块,在通讯模块中打包成响应包
把响应包数据发送给浏览器通讯模块
浏览器通讯模块解析数据并且展示返回的数据
##响应数据乱码
-为什么出现乱码,因为输出响应数据默认使用的是iso8859-1 需要把此编码改成utf-8
##发出请求时传递参数
把请求的参数写在请求地址的后面
http://localhost:8080/1712ServletDay02_01Hello/hello?name=xiaoming
通过request获取请求参数
##案例:计算 体质率BMI
页面中 有两个文本输入框 一个用来获取身高,一个用来获取体重 和一个提交按钮
bmi计算公式 bmi = 体重(kg)/身高(m)/身高(m)
根据bmi值判断体重是否正常
bmi<19 体重偏瘦="" bmi="">=19&& bmi<=25 体重正常
bmi>25 该减肥了
步骤:1. 创建页面bmi.html 页面中添加两个文本输入框和一个提交按钮
2. 创建BMIServlet在Service方法中写业务逻辑 3. 在web.xml中配置bmiservlet
因为浏览器默认会对中进行utf-8编码,但是在Servlet里面8.0以前默认是iso8859-1,8.0以后默认是utf-8,如果使用8.0以前版本解决乱码方案有两种:
new String(gender.getBytes("iso8859-1"),"utf-8");
<Connector URIEncoding="utf-8"
属于一种网络应用层的协议,规定了浏览器与web服务器之间如何通讯,以及数据包的结构 -tcp/ip协议:属于连接协议,规定了两台设备如何建立连接 -http:应用层协议基于tcp/ip协议 http协议,规定了数据包的内容和结构,规定了请求方式等内容 浏览器->打请求包->服务器->服务器解请求包 服务器->打响应包->浏览器->浏览器解响应包 http://locaohost:8888/1712ServletDay02_01Hello/hello?name=abc
GET /1712ServletDay02_01Hello/hello?name=abc HTTP/1.1 Host: localhost:8080 主机地址
Connection: keep-alive 连接状态
Upgrade-Insecure-Requests: 1
//浏览器信息
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp, / ;q=0.8
Accept-Encoding: gzip, deflate, sdch
Accept-Language: zh-CN,zh;q=0.8
Date: Tue, 03 Apr 2018 07:44:01 GMT(当前时间)
http请求包中包含:请求头和请求体
GET:
浏览器什么时候会发出get请求:
POST:
浏览器什么时候会发出post请求
当Servlet组件被tomcat容器调用执行的时候会先执行service方法,在Service方法中判断请求方式是get就访问doGet 如果是post就访问doPost
String uri = request.getRequestURI();
StringBuffer url = request.getRequestURL();
String httpVersion = request.getProtocol();
//设置响应数据类型和字符集 response.setContentType("text/html;charset=utf-8"); //设置刷新时间 response.setHeader("refresh", "3;info.html");
response.setContentType("text/html;charset=utf-8");
get请求:
new String(gender.getBytes("iso8859-1"),"utf-8");
修改server配置文件 65左右 <Connector URIEncoding=”utf-8”
post:
为什么出现乱码:在post表单提交数据的时候使用当前页面的解码格式进行编码,因为Request对象默认使用iso8859-1解码 所以需要使用以下方式解决乱码问题
解决方案:在获取参数之前添加以下代码
request.setCharacterEncoding("utf-8");
request.setCharacterEncoding("utf-8"); response.setContentType("text/html;charset=utf-8");
response.setHeader("refresh","2");
response.setHeader("refresh","2;home.html");
response.sendRedirect(request.getContextPath()+"/FindAllServlet");
request.getContextPath()
模糊匹配: 通过添加* 的方式让多个请求地址对应一个Servlet
/*
: *代表一个或多个未知,此地址会对应所有的动态资源地址(servlet地址) /abc /bcd /aaa /a/b/c /x/y
http://localhost:8080/appname/(内容任意)
/user/*
:此匹配地址必须要求请求地址中必须是
http://localhost:8080/appname/user/(内容任意)
后缀匹配 *.do
(*.action)
http://localhost:8080/appname/xxxx.do
1. 在当前应用的web.xml中查找是否有与之匹配的动态资源路径(Servlet) 2. 如果匹配到则执行相对应的Servlet 3. 如果没有匹配到会使用默认的Servlet查找是否有同名的静态资源 4. 如果有则返回资源文件 5. 如果没有则页面会显示404(找不到资源) 总结:先找动态 然后找静态 都找不到就404
properties->web settings
修改里面的名称,此时的名称为复制之前工程的名称,修改成新工程的名字 实例化: 两种情况:
<load-on-startup>1</load-on-startup>
数值越小 优先级越高 初始化: 当请求地址在web.xml中匹配到相应的Servlet的时候 web容器会通过反射实例化Servlet对象 并且调用有参数的init方法 在有参数的方法中调用了无参的init()如果需要写初始化代码 重写无参的init();
练习: 自己写一个jsp 显示当前时间
格式为 2018年10月20日 11点23分44秒
练习: 显示用户表中的所有用户信息
###cellpadding 内容距td边框的距离
###cellspacing td边框距table边框的距离
Servlet(显示 业务逻辑)
Dao数据访问
JSP(显示 业务逻辑)
Dao数据访问
##三层架构
JSP(显示)
Servlet(业务逻辑)
Dao数据访问
案例:查询所有用户
request.getRequestDispatcher("userlist3.jsp"); dispatcher.forward(request, response);注意:转发实际上就是web容器找到相对应的组件并且执行了组件的_jspService方法
<jsp:include page="file.jsp">
request.getDispatcher("")
response.sendRedirect("")
<form action="">
<a href=""></a>
不以 /
开头的路径就是相对路径,此路径相对于当前组件的位置
如果想要找到上一级的资源需要加上 ../
../../a.jsp
request.getContextPath()
/
开头的路径是绝对路径 request.getDispatcher("/jsp/a.jsp")
直接省略前面的工程名 <a href="<%=request.getContextPath() %>/jsp/a.jsp">
<form action="<%=request.getContextPath() %>/jsp/helloServlet">
response.sendRedirect("<%=request.getContextPath() %>/jsp/a.jsp")
cookie默认是保存在内存中,浏览器关闭则清除,如果设置了时间为0则立即清除,如果设置时间为正整数,则保存在磁盘中,时间到后自动删除
工作原理:
setCookie
的形式把数据存放到响应的消息头中,然后浏览器再次访问服务器时,会将Cookie数据放在请求的消息头中,这样服务器就能够得到之前请求时保存的一些数据,这样多次请求就能建立联系 服务器如何添加cookie:
//创建一个cookie对象 Cookie cookie= new Cookie("name", "xiaoming"); //设置cookie的过期时间,如果设置为0表示立即清除,如果没有设置那么浏览器关闭之后就会清除 cookie.setMaxAge(100); //添加到响应头中,并且返回给浏览器 response.addCookie(cookie);
cookie时间:
cookie.setMaxAge(100);
单位是秒 获取cookie的值
// 获取Cookie,返回的是一个数组 Cookie[] cookies = request.getCookies(); //如果Cookies存在,读取 if (cookies != null) { for(Cookie cookie : cookies){ System.out.println(cookie.getName()+" : " + cookie.getValue()); } }else { System.out.println("其中没有cookie"); }
cookie的路径
如果不设置路径,默认会以当前组件的路径为准,只有当访问地址为当前组件地址或者组件地址的子地址时才会带上cookie
http://localhost:8080/web1/cookie/setCookieServlet
,那么我们的获取添加的cookie的servlet地址只有是 http://localhost:8080/web1/cookie
这个地址的子地址(后代),比如 http://localhost:8080/web1/cookie/user/getCookieServlet
为cookie设置路径
举例:
/a
/a/servlet1
: yes /b/servlet2
: no cookie的编码问题
cookie只能保存英文,不能保存中文,如果需要保存中文,那么需要编码
中文编码
String name="小明"; //对中文进行url编码 name=URLEncoder.encode(name,"utf-8"); //创建一个cookie对象 Cookie cookie= new Cookie("name", name); //设置cookie的过期时间,如果设置为0表示立即清除,如果没有设置那么浏览器关闭之后就会清除 cookie.setMaxAge(100); System.out.println(cookie.getPath()); //添加到响应头中,并且返回给浏览器 response.addCookie(cookie);
将获取的中文cookie解码输出
// 获取Cookie,返回的是一个数组 Cookie[] cookies = request.getCookies(); //如果Cookies存在,读取 if (cookies != null) { for(Cookie cookie : cookies){ String value=cookie.getValue(); //把cookie的值取出,然后url解码 value=URLDecoder.decode(value,"utf-8"); System.out.println(cookie.getName()+" : " + value); } }else { System.out.println("其中没有cookie"); }
cookie的限制
@Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Cookie[] cookies = request.getCookies(); Map<String, String> map = getValues(cookies); //获取map String stringCount = map.get("count"); // 获取指定的value if (stringCount == null) {// 第一次请求 stringCount = "1"; // 设置访问次数为1 } else {// 不是第一次请求 // 请求次数+1 stringCount = "" + (Integer.parseInt(stringCount) + 1); } Cookie cookie = new Cookie("count", stringCount); // 把运行次数放置到cookie中 response.addCookie(cookie); // 添加cookie,如果前面已经存在了,那么相当于更新cookie的值 System.out.println(stringCount); } /** * 将cookie数组中的键值对存放到Map中,这样就能判断出这个cookie中是否含有指定的key */ public Map<String, String> getValues(Cookie[] cookies){ Map<String, String> map = new HashMap<String, String>(); if (cookies != null) { for (Cookie cookie : cookies) { map.put(cookie.getName(), cookie.getValue()); } } return map; }
实现:
在每次跳转到登录页面的时候都需要经过一个Servlet,这个Servlet的作用是获取cookie的值,并且存放在request域中,这样在login.jsp页面中就可以使用这个值
login.jsp
<form action="/Servlet01/RememberLoginServlet" method="post"> <table cellpadding="0" cellspacing="0" border="0" class="form_table"> <tr> <td valign="middle" align="right">username:</td> <td valign="middle" align="left"><input type="text" class="inputgri" name="username" value="<%=request.getAttribute("username") %>" /></td> </tr> <tr> <td valign="middle" align="right">password:</td> <td valign="middle" align="left"><input type="password" class="inputgri" name="password" value="<%=request.getAttribute("password") %>" /></td> </tr> <tr> <td></td> <td valign="middle" align="left"> <input type="checkbox" name="isRemember">记住用户名和密码一周 </td> </tr> </table> <p> <input type="submit" class="button" value="Submit »" /> </p> </form>
验证用户,保存信息到cookie中的servlet
@Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("UTF-8"); // 设置中文格式 //设置响应字符集必须写在获取输出对象的前面 response.setContentType("text/html;charset=utf-8"); PrintWriter writer=response.getWriter(); // 获取用户名和密码 String username = request.getParameter("username"); String password = request.getParameter("password"); String isRemeber = request.getParameter("isRemember"); // 登录流程 Connection connection = null; PreparedStatement statement = null; ResultSet resultSet = null; try { connection = DBUtils.getConn(); // 获取连接 String sql = "select count(*) c from user where username=? and password=?"; statement = connection.prepareStatement(sql); //创建预编译对象 //设置占位符的值 statement.setString(1, username); statement.setString(2, password); resultSet = statement.executeQuery(); // 执行查询语句 //遍历查询结果集,如果count>0 表示登录成功,如果=0表示用户名或密码错误 while (resultSet.next()) { int count = resultSet.getInt("c"); // 获取总数 if (count > 0) { System.out.println("登录成功"); // 判断是否记住密码 //如果设置了记住密码,那么就将此时的用户名和密码保存在cookie中 if (isRemeber != null) { //将username和password添加到cookie中 Cookie cookie=new Cookie("loginInfo", username+","+password); cookie.setMaxAge(7*24*3600); //设置时间为一周,单位为秒 response.addCookie(cookie); } //跳转到首页 request.getRequestDispatcher("home.jsp").forward(request, response); } else { System.out.println("登录失败,用户名或密码错误"); response.sendRedirect("/Servlet01/ShowLoginCookieServlet"); //重定向到登录界面 } } } catch (Exception e) { e.printStackTrace(); writer.write("服务器出错....."); } finally { DBUtils.close(connection, statement, resultSet); // 关闭资源 } }
获取cookie值,存放到request域中,便于在login.jsp页面中访问到信息
@Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Cookie[] cookies = request.getCookies(); Map<String, String> map = getValues(cookies); String loginInfo = map.get("loginInfo"); // 获取cookie的值 String username = ""; String password = ""; if (loginInfo != null) { username = loginInfo.split(",")[0]; // 分割字符串,获取信息 password = loginInfo.split(",")[1]; } request.setAttribute("username", username); request.setAttribute("password", password); request.getRequestDispatcher("login.jsp").forward(request, response); } /** * 将cookie数组中的键值对存放到Map中,这样就能判断出这个cookie中是否含有指定的key */ public Map<String, String> getValues(Cookie[] cookies){ Map<String, String> map = new HashMap<String, String>(); if (cookies != null) { for (Cookie cookie : cookies) { map.put(cookie.getName(), cookie.getValue()); } } return map; }
服务端为了保存状态(数据)创建的一个特殊的对象,session数据会保存在服务器
工作原理
HttpSession session=request.getSession(boolean flag)
session默认时间是在服务器保存30分钟
如何修改session存活时间
修改配置文件
<session-config> <session-timeout>30</session-timeout> </session-config>
通过代码设置时间
session.setMaxInactiveInterval(int mils);
单位为秒 session.invalidate()
session.removeAttribute(key)
String pw="admin"; BASE64Encoder encoder=new BASE64Encoder(); String newPW=encoder.encode(pw.getBytes("utf-8")); System.out.println(newPW); //解密 BASE64Decoder decoder=new BASE64Decoder(); String oldPw=new String(decoder.decodeBuffer(newPW),"utf-8"); System.out.println(oldPw);
cookie: 优点不占用服务器资源,缺点:大小有限制4k 数量限制200左右 内容有限制只能存放字符串,cookie不够安全而且有些浏览器可以模拟cookie数据
Session: 优点 :安全(因为数据保存在服务器)大小无限制,保存数据类型丰富, 缺点 : 占用资源,浏览器关闭后Session则失效,因为session的是状态是存储在cookie中的seessionid决定的。
new - > Filter
这样就创建一个过滤器,其中的类实现了Filter这个接口
public class MyFilterimplements Filter{ public MyFilter(){ } public void destroy(){ System.out.println("过滤器被销毁"); } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("过滤器执行"); chain.doFilter(request, response); } public void init(FilterConfig fConfig)throws ServletException { System.out.println("过滤器初始化"); } }
这个类中同样有init和destroy方法,但是实现代码逻辑实在doFilter()这个方法中
<!-- 配置Filter 的name和class --> <filter> <filter-name>MyFilter</filter-name> <filter-class>cn.filter.MyFilter</filter-class> </filter> <!-- 配置Filter的过滤的url,其中的name是前面定义好的 --> <filter-mapping> <filter-name>MyFilter</filter-name> <!-- /* 拦截所有的Servlet,但是也拦截器了这个路径下的jsp ,如果设置成/MyServlet,那么只拦截这一个Servlet--> <url-pattern>/*</url-pattern> </filter-mapping>
如果出现了敏感字符禁止访问
步骤
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException { HttpServletRequest req=(HttpServletRequest)request; //继续执行下面的Filter和Servlet,没有这个方法,那么将不会执行 chain.doFilter(request, response); }
<init-param>
设置初始化值 其中的
<filter> <filter-name>CommentFiletr</filter-name> <filter-class>cn.filter.CommentFiletr</filter-class> <init-param> <param-name>word</param-name> <param-value>美女,我操</param-value> </init-param> </filter>
获取其中的值
public class CommentFiletrimplements Filter{ private FilterConfig config; //定义成员变量FilterConfig对象 public CommentFiletr(){ } public void destroy(){ } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException { String word=this.config.getInitParameter("word"); //获取初始化值 chain.doFilter(request, response); } //初始化方法 public void init(FilterConfig fConfig)throws ServletException { this.config=fConfig; } }
定义: web服务器启动的时候会为每一个应用创建一个符合ServletContext接口的对象
特点:
应用场景:
<context-param>
即可 <context-param> <param-name>name</param-name> <param-value>陈加兵</param-value> </context-param>
在组件中获取ServletContext(在任何组件中都可以获取)
在 Servlet
中获取
protected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException { ServletContext context=this.getServletContext(); //获取对象 String name=context.getInitParameter("name"); //获取name属性的值 }
在 Filter
中获取
//初始化方法 public void init(FilterConfig fConfig)throws ServletException { ServletContext context=fConfig.getServletContext(); String name=context.getInitParameter("name"); }
ServletContext > Session > Request > PageContext
如何选择传递数据的域:符合需求的域中,选择范围最小的
new --- > Listener ---> 类名 ---> next -- > 选择对应的Listener
具体的选项如下图
其中Liftcycle 是 生名周期金监听器 其中可以监听三大域的创建和销毁
-Change to Attributes 是三大域绑定删除数据监听器
<listener> <listener-class>cn.listener.MyListener</listener-class> </listener>
因为我们是统计在线人数,因此我们需要在jsp页面中显示出人数,我们需要将在线人数这个变量存放在ServletContext才能实现共享,这样只有当web容器关闭才会清空其中的在线人数
如果存放在session中,那么当浏览器关闭就会清空session中的数据,或者到了指定的时间也会清空,因此我们不能存放在Session
创建一个监听Session的监听器
public class MyListenerimplements HttpSessionListener{ //Session创建时调用的方法 public void sessionCreated(HttpSessionEvent sessionEvent){ System.out.println("会话开始"); // 取出当前在线人数 ServletContext context = sessionEvent.getSession().getServletContext(); // 得到ServletContext Integer count=(Integer) context.getAttribute("count"); //获取当前的在线人数 // 如果count是第一次,那么此时的count就是null,因为这里还没有设置这个上下文参数 if (count == null) { count = 1; } else { count++; } // 将在线人数保存回去 context.setAttribute("count",count); } //Session销毁时调用的方法 public void sessionDestroyed(HttpSessionEvent event){ System.out.println("会话结束"); ServletContext context = event.getSession().getServletContext(); Integer count=(Integer) context.getAttribute("count"); //获取当前的在线人数 count--; // 直接人数-1 // 将此时的人数保存回去 context.setAttribute("count",count); } }
创建一ServletContext生命周期监听器,在ServletContext创建的的方法中读取数据库中的数据并将数据保存在ServletContext中,因为ServletContext在容器创建的时候就会创建,因此在web容器开启的时候就会读取数据库中的信息
我们在Servlet中直接读取ServletContext中的数据即可,不同在请求Servlet的时候从数据库中读取,提高Servlet的响应效率
public class CacheListenerimplements ServletContextListener{ //ServletContext销毁的时候调用 public void contextDestroyed(ServletContextEvent event){ System.out.println("销毁"); } //ServletContext初始化的时候调用 public void contextInitialized(ServletContextEvent event){ ServletContext context=event.getServletContext(); //获取ServletContext对象 EmpDao empDao=new EmpDao(); //创建Dao对象,用于读取数据库中的信息 List<Emp> emps=empDao.findAll(); //获取所有的数据 context.setAttribute("emps", emps); //添加到ServletContext中 } }
MyServlet、MyListener(监听ServletContext),MyFilter
web容器启动 – > MyListener(监听) — > MyFilter实例化 – > 请求 —> MyFilter(doFilter) —> 执行MyServlet
public class ThreadSafeServletextends HttpServlet{ private int count = 0; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println(Thread.currentThread().getName() + ":开始执行" + count); try { Thread.sleep(5000); //线程睡眠5s } catch (InterruptedException e) { e.printStackTrace(); } count++; System.out.println(Thread.currentThread().getName() + ":执行完毕" + count); } }
public class ThreadSafeServletextends HttpServlet{ private int count = 0; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //同步代码块 synchronized (this) { System.out.println(Thread.currentThread().getName() + ":开始执行" + count); try { Thread.sleep(5000); //线程睡眠5s } catch (InterruptedException e) { e.printStackTrace(); } count++; System.out.println(Thread.currentThread().getName() + ":执行完毕" + count); } } }
java代码的写法
<% %>
写java代码,任意java代码都行,转化成Servlet的时候直接是写在service方法体中 <%! %>
声明变量或者方法,转换成Servlet的时候直接作为其成员变量或者成员方法 <%= %>
java表达式,返回的是一个值 指令
<%@ page>
: import导包 contentType pageEncoding
tablib : 引入标签库
application session request
pageContext
: 用于在同一个jsp中共享数据,常用方法有setAttribute(),getAttribute(),removeAttribute()
<% pageContext.setAttribute("name", "陈加兵"); %> <h1><%=pageContext.getAttribute("name") %></h1>
response
: 类型HttpServletResponse,用于处理响应数据和重定向,因为有out,更多使用的是out
out
: 类型为JSPWriter,用于输出数据
page
: page就是jsp本身,因为jsp最终会转成Servlet,page相当于this
exception
: 异常对象,用于获取异常信息,只有当page指令里面添加了 isErrorPage=true
的时候才能使用
config
: 类型为ServletConfig,用于获取配置文件中初始化参数
<!--注释内容--> <%-- 注释内容 --%>
将JSP转成Servlet
调用Servlet
${}
) ${对象名.属性名}
,假设一个对象user,访问其中的name属性,我们可以使用 ${user.name}
,这个相当于调用了 user.getName()
方法 ${user.name}
会先从pageContext域中查找如果有则用,如果没有会到request域中查找,如果没有再到session域中查找,如果没有再到ServletContext中查找
""
,如果没有获取到对象调用对象的方法不会报空指针异常,仍然输出空字符串 指定域获取 ${requestScope.user.name}
相当于 request.getAttribute("user").getName()
${user['name']}
个人不推荐使用
直接使用 ${param.请求参数名}
获取指定的请求参数
${param.name}
相当于 request.getParameter("name")
${paramValues.参数名[index]}
获取多个同名参数
request.getParameterValues("参数名")[index]
+
只能做求和运算,不能字符串拼接 ${true and false}=false
, ${true and true}=true
, ${true or false}=true
==
, !=
, >=
, <
, >
, <=
, &&
, ||
如: ${age<30}
可以直接在EL表达式比较大小,返回的也是false和true,可以用来判断,如下:
${1<2}=false
, ${(10*10)>200}=true
, ${age>11&&age<20}
empty
判断是否为空(空字符串或者值为null)
${empty str}
判断字符串是否为空 ${empty user}
判断对象user是否为空 java standard tab lib (java标准标签库)
jstl是Apache开发的一套jsp标签
导入jstljar包,使用maven,在pom.xml中添加依赖
<dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency>
通过tablib指定引入标签库
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
, uri:是标签库的命名空间,代表标签库的唯一标识,prefix :别名或前缀 几个核心标签
if标签, <c:if test="">
test中填写的是判断条件,使用EL表达式
<% request.setAttribute("age", 22); %> <c:if test="${requestScope.age>20 }"> <h1><c:out value="年龄大于20"></c:out></h1> </c:if> <c:if test="${requestScope.age>10 }" var="result" scope="session"> <h2>此时的判断结果为 : ${sessionScope.result }</h2> </c:if>
choose标签 (相当于switch case)
<% User user=new User(); user.setUsername("libai"); user.setPassword("admin"); request.setAttribute("user", user); %> <c:choose> <c:when test="${user.username=='libai' && user.password=='admin' }"> <h1>登录成功</h1> </c:when> <!-- 其他的任何类型的判断,只要不是when中的,都在这里执行,相当于else --> <c:otherwise> <h1>登录失败</h1> </c:otherwise> </c:choose>
forEach标签 相当于java中的forEach,由于遍历集合或者数组
varStatus : 遍历的状态,如果需要得到遍历对象的下标调用 index
,如果想要得到遍历对象是集合中的第几个调用 count
<table width="500" border="1"> <tr> <th>用户名</th> <th>密码</th> <th>性别</th> <th>级别</th> <th>下标</th> <th>第几个</th> </tr> <c:forEach var="user" items="${requestScope.users }" begin="0" end="19" step="1" varStatus="s"> <c:if test="${s.index%2==0 }"> <tr id="row1"> </c:if> <c:if test="${s.index%2!=0 }"> <tr id="row2"> </c:if> <td>${user.username }</td> <td>${user.password }</td> <td>${user.gender }</td> <td>${user.level }</td> <!-- 下标 --> <td>${s.index }</td> <!-- 第几个 --> <td>${s.count }</td> </tr> </c:forEach> </table>