jsp

  java server page

  java 页面技术

  sun公司制定额一种服务器端动态页面生成技术规范

        jsp实际上是一个以.jsp为后缀的文件,该文件主要由html和少量的java代码组成,容器会将jsp文件先转换成一个对应额servlet然后再去执行.


jsp文件:

    注释<!-- 注释内容-->注释的内容可以是java 代码 如果是java代码会被容器执行

    <%--z注释内容--%> 注释的内容不能有java 代码,如果有 会被容器忽略

    html(css javascript)

    java代码

        java代码片段

            <%    java代码    %>

        jsp表达式

            <%=  java表达式    %>

        jsp 声明 <%! %>   可以写方法

        jsp隐含对象

            在jsp 文件里面,不用声明和创建,就以直接使用的对象

            容器会自动添加声明 创建这些对象的语句

         容器将jsp转换为 servlet 会自动添加

            1. 与输入/输出有关的对象: request、response、out
                 2. 与属性作用域有关的对象:session、application、pageContext
                   3. 与Servlet 相关对象:page、config
                     4. 与错误处理有关的:exception

            

requestHttpServletRequest类的实例


responseHttpServletResponse类的实例


outPrintWriter类的实例,用于把结果输出至网页上


sessionHttpSession类的实例


applicationServletContext类的实例,与应用上下文有关


configServletConfig类的实例

在web.xml 

<servlet>
    <servlet-name>one</servlet-name>
    <jsp-file>/one.jsp</jsp-file>
    <init-param>
        <param-name>name</param-name>
        <param-value>lmdtx</param-value>
    </init-param>
</servlet>
<serlvet-mapping>
    <servlet-name>one</servlet-name>
    <url-pattern>one</url-pattern>
</servlet-mapping>


pageContextPageContext类的实例,提供对JSP页面所有对象以及命名空间的访问,容器会为每一个jsp实例 jsp 对应的那个servlet对象 创建唯一的一个pasgeContext对象,这个对象会一直存在,除非jsp实例被销毁    类似 sessionContext  可以绑定数据 这个数据只有对应的jsp实例可以访问  他还可以找到其他的8个隐含对象


page类似于Java类中的this关键字(基本不用)


ExceptionException类的对象,代表发生错误的JSP页面中对应的异常对象(必须是一个错误处理页面才能用) 也就是<%@ isErrorPage="true"%>


    jsp执行

        容器要将jsp文件装换成一个java类   就是一个servlet

            html(css,js)  放在service 方法里面 用out.write 输出

            java代码片段   放在service 方法里面  照搬

        容器对这个servlet 类尽心编译,实例化,初始化 调用servlet 方法处理请求


        java 表达式   使用out.println()

    

    指令

        告诉容器在将jsp文件装换为java类时做的一些额外的处理

        比如导包

        <%@ 指令名称 属性名称=属性值 %>

        page定义网页依赖属性,比如脚本语言、error页面、缓存需求等等

            <%@ page import ="java.util.*" %>

            buffer     指定out对象使用缓冲区的大小
            autoFlush     控制out对象的 缓存区

            pageEncoding 告诉容器这个jsp文件的编码格式utf-8格式  有部分的容器默认使用iso-8859-1解码  添加这个属性,容器可以进行正确的解码

            contentType     设置response.setContentType的内容指定当前JSP页面的MIME类型和字符编码            

            errorPage     指定当JSP页面发生异常时需要转向的错误处理页面
            isErrorPage     指定当前页面是否可以作为另一个JSP页面的错误处理页面
            extends     指定servlet从哪一个类继承
            import     导入要使用的Java类
            info     定义JSP页面的描述信息
            isThreadSafe     指定对JSP页面的访问是否为线程安全
            language     定义JSP页面所用的脚本语言,默认是Java
            session     指定JSP页面是否使用session
            isELIgnored     指定是否执行EL表达式
            isScriptingEnabled     确定脚本元素能否被使用

        include包含其他文件

            作用 将file 属性所指定的文件的内容插入到指令所在的位置

            <%@include file="要包含的文件(jsp;html  都可以 )"%>

        taglib引入标签库的定义

        <%@ page session="true" %>  true/false  默认 true

        当值为false ,容器就不再添加获得session对象的代码.

        <%@ errorPage = "xxx.jsp"%>

        <%@ isErrorPage="true"%> true/false 



转发  Servlet 调用 jsp


1个web 组件servlet 或者jsp 之类的  将未完成的处理 通过容器交给另外一个web组件继续完成

常用 一个servlet 获得数据之后  转发给 jsp  由  这个 jsp 来负责展现这些数据



1绑定数据到request 对象上

    reuest.setAttribute(String name,Objetct obj);


url   转发的目的地址

2获得转发器 RequestDispatcher rd = request.getRequestDispatcher(String url);


3转发  rd.forward(request,response);


Object request.getAttribute(String name);//根据绑定名称找到绑定值,  如果值不存在 返回null



转发的特点,  

转发后  浏览器的地址栏的地址是不变的

转发的目的地 仅限于同一个应用.



转发需要注意的问题. 转发之前,不能调用 out.close()

转发之前 容器会先清空response 对象上的缓存的数据




处理 servlet 运行的时候产生的异常

使用转发  

将异常交给servlet 容器来处理

 将异常抛给容器,  throw new ServletException(e);

 配置一个错误处理页面  告诉容器,捕获到指定的异常以后调用location指定的页面     

<error-page>
      <exception-type>javax.servlet.ServletException</exception-type>
      <location>/error.jsp</location>
      </error-page>

路径问题

    链接地址 表单提交地址 重定向地址 转发的地址

   相对路径  不以 "/" 的路径

   绝对路径  以"/"开头的路径

   链接地址 表单提交地址 重定向地址从应用名开始写,

    转发从应用名之后开始写


    获得应用名:  返回  /应用名

    String request.getContextPath()


状态管理 

    将浏览器与web服务器之间多次交互当做一个整体来看待 并且 将多次交互所涉及的数据 保存下来

    如何进行状态管理:

        客户端的状态管理

            将状态保存在客户端,比如 cookie

        服务器端的状态管理

            将状态保存在服务器端 session



cookie  

    当流浪器访问服务器时,服务器会发送少量的数据给浏览器   使用 set-cookie 消息头

    浏览器会将这些数据保存下来(可以是内存,也可以是硬盘上)当浏览器再次访问服务器时,会将之前保存的这些数据发送给服务器(使用 cookie 消息头)


    创建cookie

    Cookie c = new Cookie(String name,String value);

    response.addCookie(c);

    查询cookie

    Cookie[] cookies = request.getCookies();

    注意:该方法有可能返回null

    String cookie.getName();

    String cookie.getValue();

    cookie 的生存时间 

        cookie.setMaxAge(int seconds);

        seconds 单位是秒

        可以  >0  浏览器会把cookie 保存到硬盘上超过指定的时间 浏览器会删除这个cookie

            <0缺省值  浏览器会把cookie保存在内存里面 只要关闭浏览器cookie就会被销毁

              =0 删除cookie

                    要删除一个名叫user的cookie  

                        Cookie c = new Cookie("user","");

                        c.setMaxAge(0);

                        response.addCookie(c);


    编码问题

        cookie 只能保存合法的ascii字符

        中文不是ascii 字符  需要将其转换成合法的ascii字符

        String URLEncoder.encode(String str,String code);

        URLDecoder.decode(String str,String code);

   

    路径问题

        浏览器在访问服务器的某个地址的时候,会比较cookie的路径是否与该地址匹配只有匹配的cookie才会发送 

    匹配的规则  cookie 有一个缺省的路径,值等于创建该cookie的web组件的路径

        

    要访问的地址必须是cookie的路径或者其子路径


    缺省的路径  可以用 cookie.setPath(String path);  一般情况下  将path设置为应用名



创建一个cookie

    创建一个cookie 对象

        Cookie c = new Cookie("user","lmdtx");//英文

        Cookie zc = new Cookie("user",URLEncoder.encode("中文","utf-8"));

        c.setMaxAge(3600);

        c.setPath("/应用名");

        response.addCookie(c);


    cookie 的限制

        cookie 可以被用户禁止

        cookie 保存在客户端,不安全,敏感数据需要加密

        cookie 保存的数据大小有限制  大约是4k左右  和浏览器有关

        浏览器保存的cookie的数量也有限制,大约是300个左右  和浏览器有关

        

session 会话 浏览器 访问服务器的时候服务器会创建一个session对象这个对象有一个唯一的id  sessionId  服务器在默认情况下  会使用cookie机制将sessionId 发送给浏览器  浏览器再次访问服务器时  会将sessionId发送给服务器,服务器依据sessionId 找到之前创建的session对象

    获得一个session对象

        接口    工厂

        HttpSession s = request.getSession(boolean flag);

        当flag = true  先查看请求当中是否有sessionId 如果没有册创建一个session对象,如果有 就根据sessionId 查找对应的session对象 如果找到 就返回,找不到,就创建一个新的session对象

        当flag=false  先查看请求当中是否有sessionId 如果没有,返回null 如果有 就根据sessionId 查找对应的session对象, 找到 返回,找不到 返回null

    HttpSession s = request.getSession()

     等于 HttpSession s = requset.getSession(true);


  常用方法

        String session.getId();//获得sessionId

        setAttribute(String name,Object obj); //绑定 

        Object getAttribute(String name);//获取

        removeAttribute(String name);//移除绑定

       绑定的是对象....

    session 超时

        容器会将空闲过长的session对象删除掉

            容器默认超时时间限制一般是30分钟

        修改容器缺省的超时限制

            tomcat conf/web.xml   session-config  session-timeout 

        也可以放到 应用中的web.xml  缩小改动范围

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

    //空闲时间

    setMaxInactiveInterval(int seconds);

    删除session    

        invalidate()


    session 验证

        登录

        建表

    验证码

package util;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Random;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

public class CheckcodeServlet extends HttpServlet {

	private int width=80;
	private int height = 30;
	public void service(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		//绘图
			//创建一个内存映像对象
		BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_BGR);
			//获得 画笔
		Graphics g = image.getGraphics();
			//给画笔设置颜色
		Random r = new Random();
		g.setColor(new Color(r.nextInt(255),r.nextInt(255),r.nextInt(255)));
			//给画布设置背景颜色
		g.fillRect(0, 0, width, height);
			//将一个随机数画在画布上
		String str= "QAZWSXEDCRFVTGBYHNUJMIKOLP1234567890";
		String number = "";
		for(int i=0;i<4;i++){
			number += str.charAt(r.nextInt(str.length()));
		}
		//把验证码绑定到session对象上
		HttpSession session = request.getSession();
		session.setAttribute("number", number);
		g.setColor(new Color(r.nextInt(255),r.nextInt(255),r.nextInt(255)));
			//设置字体
		g.setFont(new Font(null,Font.ITALIC,20));
		g.drawString(number, 10,20);
		for(int i =0;i<8;i++){
			g.setColor(new Color(r.nextInt(255),r.nextInt(255),r.nextInt(255)));
			g.drawLine(r.nextInt(width), r.nextInt(height), r.nextInt(width), r.nextInt(height));
			
		}
		//将图片压缩输出到浏览器
		response.setContentType("image/jpeg");
		OutputStream ops = response.getOutputStream();
			//write方法将原始图片压缩,然后发送给response对象
		javax.imageio.ImageIO.write(image, "jpeg", ops);
	}
}
                        String number1 = request.getParameter("number");
			HttpSession session = request.getSession();
			String number2 = (String)session.getAttribute("number");
			System.out.println(number1);
			System.out.println(number2);
			if(!number1.equalsIgnoreCase(number2)){
				//验证码错误
				request.setAttribute("number_error", "验证码错误");
				request.getRequestDispatcher("login.jsp").forward(request, response);
				return;
			}

 

	<tr>
		<td valign="middle" align="right">
		验证码:
		</td>
		<td valign="middle" align="left">
			<input type="text" class="inputgri" name="number" /><br/>
			<img  src="checkcode"  onclick = "this.src='checkcode?'+Math.random();">
			<%
				String msg2 = (String) request.getAttribute("number_error");
			%>
			<span style="color:red;"><%=((msg2 == null)?"":msg2)%></span>
		</td>
	</tr>

   加密

        保存 密码使用摘要加密

            不可逆性:按照摘要加密算法生成的密文(也叫摘要)即使知道了加密算法,也不能够反推出明文

            唯一性:不同的明文,对应唯一的摘要

       

package util;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import sun.misc.BASE64Encoder;

public class MD5Util {
	public static String encrypt(String str) throws NoSuchAlgorithmException{
		MessageDigest md = MessageDigest.getInstance("md5");
		byte[] buf = md.digest(str.getBytes());
		//要将字节数组转换成一个字符串
		BASE64Encoder encoder = new BASE64Encoder();
		return encoder.encode(buf);
	}
}


session 默认是 使用 cookie 的  如果 cookie 被禁止 还要使用 session  也是可以的

可以使用URL 重写来解决 这个问题.使链接中有 jsessionid

浏览器访问服务器上的某个地址时,需要使用 服务器提供的地址  这个地址后面  会添加sessionId

1==>response.encodeURL(String url);    这种方法用于链接地址,表单提交地址的处理

2==> response.encodeRedirectURL(String url);  这个用于重定向地址的处理

    response.redirect(response.encodeRedirectURL("重定向地址"));

3==>  转发不需要考虑,  转发是服务器内部的


session 和cookie 相比

  session 安全(状态保存在服务器端)

  cookie  将状态保存在浏览器端

  session 保存的数据更大

  cookie  保存的大约4k 

  session 保存的数据类型是任意的

  cookie  只能保存字符串

  session 对服务器的要求高,保存在服务器端,会占用服务器更多的内存空间

  cookie  在浏览器,不会占用服务器


过滤器


servlet 规范当中定义的一种特设的组件,用来拦截servlet 容器的调用过程并进行相应的处理


    写一个java类实现Filter接口

    在doFilter 方法里面 编写相应的拦截处理

    配置过滤器 在web.xml 让容器哪一些请求需要拦截


容器启动,就会将过滤器实例化  容器会立刻 调用init方法  初始化 init方法只会执行一次容器会事先创建好一个符合 FilterConfig接口要求的对象  FilterConfig提供了getInitParameter 方法来访问过滤器的初始化参数


容器收到请求之后,会调用doFilter 方法来处理  类似 servlet的service方法

容器会将事先创建好的requset 和response对象作为参数传递进来 如果调用了FilterChain的doFilter方法表示让容器继续调用后续的过滤器  如果没有过滤器了 就 调用servlet


容器在销毁过滤器之前, 会调用destroy方法 这个方法也只会执行一次


过滤器 web.xml 配置 一般写在 servlet 前面


<url-pattern>/*</url-pattern>

所拦截的地址 /* 所有


  <filter>
  	<filter-name>filter1</filter-name>
  	<filter-class>web10.CommentFilter1</filter-class>
  </filter>
  <filter-mapping>
  	<filter-name>filter1</filter-name>
  	<url-pattern>/*</url-pattern>
  </filter-mapping>


过滤器的优先级

    当有多个过滤器都满足过滤条件,则容器按照 <filter_mapping>出现的先后顺序来调用哥哥过滤器


初始化参数 

    

filter 可以接受一些参数。  

init-param的param-name 就是参数名 

 param-value就是参数值,支持多个参数

每一个 filter 都有一个 init 方法

可以再这个 方法中通过 getInitParamter("key"); 

key 就是 param-name的值,来获取对应的参数值

String FilterConfig.getInitParamenter(String paramNmae);

常用的就是设置编码过滤器

例如

<init-param>

<param-name>encoding</param-name>

<parma-value>UTF-8</param-vaue>

</init-param>


过滤器

可以实现代码的 可插拔性  增加或者减少某个功能模块,不会影响程序的正常执行 


可以将多个模块相同的处理逻辑几种卸载过滤器里面,方便代码的维护


监听器

servlet 规范当中定义的一种特殊的组件,用于监听servlet容器产生的事件并进行相应的处理

容器产生的事件主要有两大类

声明周期相关的事件 容器创建或者销毁 request  session servlet上下文产生的时间

绑定相关的事件  容器调用了 request session servlet 上下文的setAttribute removeAttribute 产生的事件


写一个java类 实现相应的监听器

将监听处理逻辑卸载相应的方法里面

注册监听器

  <listener>
  <listener-class>web.CountListener</listener-class>
  </listener>


servlet 上下文

    容器在启动的时候 会为每一个web 应用 都创建一个符合ServletContext接口要求的对象,这个对象就是servlet上下文  这个对象有 唯一性,一个web应用 一个servlet上下文 ;一直存在 只要容器不关闭 servlet上下文会一直存在

    如何获得servlet上下文  

        ServletConfig

        FilterConfig

        GenericServlet

        HttpSession

        都提供了getServletContext方法  来获得上下文

    servlet的上下文的作用

        绑定数据

        setAttribute removeAttribute,getAttribute    

    request

    session

    servlet

        都可以绑定数据  但是存在的时间不一样  request<session<servlet 上下文

        尽量使用时间短的

        访问的范围不一样  

request 对象上绑定的数据可以被同一个请求中所涉及的各个组件访问 

session 绑定的数据可以被同一个会话所涉及的组件访问 

servlet上下文绑定的数据可以被同一个应用所涉及的所有组件访问 

    

    访问全局的初始化参数

    同一个应用所包含的各个组件都可以访问的初始化参数


    web.xml 中 

    <context-param>

        <param-name></param-name>

        <param-value></param-value>

    </context-param>

    使用 servlet 上下文方法

    ServletContext.getInitParamenter("String paramName");

    

    根据逻辑路径  获得实际部署时的物理路径.

    String getRealPath(String path);









web.xml 配置

    全局初始化参数

    过滤器

    监听器

    servlet

     错误处理页面

    首页

    


启动容器马上开始执行相关任务 之后每间隔5S 执行一次任务

package web12;

import java.util.Timer;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

public class TaskListener implements ServletContextListener{
	private Timer  timer = new Timer();
	@Override
	public void contextDestroyed(ServletContextEvent arg0) {
		System.out.println("销毁");
		timer.cancel();
	}

	@Override
	public void contextInitialized(ServletContextEvent arg0) {
		System.out.println("创建");
		timer.schedule(new MyTask(), 0,5000);		
	}

}
package web12;

import java.util.Date;
import java.util.TimerTask;

public class MyTask  extends TimerTask{

	@Override
	public void run() {
		System.out.println(new Date());
		
	}

}
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
  <display-name>web11</display-name>
  <listener>
  	<listener-class>web12.TaskListener</listener-class>
  </listener>
</web-app>



上传文件

    设置表单的提交方式为post

    设置表单的enctype属性为 "multipart/form-data"

    <form action ="" method="post" enctype="multipart/form-data">

    在服务器端,不能使用request.getParameter 方法.  使用 这个方法 返回值 是null

    使用InputStream request.getInputStream 方法  自己分析InputStream  还和浏览器有关系,一般使用一些工具来分析这个流 不自己分析  工具:apache commons-fileupload

在Servlet 中使用commons-io和commons-fileupload 上传文件


报错:Java.lang.NullPointerException: No FileItemFactory has been set.

ServletFileUpload sfu = new ServletFileUpload(factory);

未传入 factory



package web12;


import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

public class FileUpload extends HttpServlet {

	public void service(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		response.setContentType("text/html");
		//factory 对象为解析器提供解析时的一些缺省的配置
		DiskFileItemFactory factory =new DiskFileItemFactory();
		//创建一个解析器
		ServletFileUpload sfu = new ServletFileUpload(factory);
		//使用解析器解析inputStream
		try {
			//解析器将每一个表单域中的数据封装到一个FileItem对象里面
			List<FileItem> items = sfu.parseRequest(request);
			//遍历 items 集合  就可以读取每一个表单域的数据
			for(int i =0;i<items.size();i++){
				FileItem item = items.get(i);
				if(item.isFormField()){
					//普通的表单域
					String name =item.getString();
					System.out.println(name);
				}else{
					//上传文件域
					ServletContext sctx = getServletContext();
					//根据逻辑路径,获得实际部署的时候的物理路径
					String path = sctx.getRealPath("upload");
					String fileName = item.getName();
					File file = new File(path+File.separator+fileName);
					item.write(file);
					System.out.println("ok");
				}
				
			}
		} catch (FileUploadException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		PrintWriter out = response.getWriter();
		out.close();
	}

}
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
  </head>
  <body>
    <form action="fileUpload" method="post" enctype="multipart/form-data">
    	name:<input  name="name"/><br/>
    	file: <input type="file" name="file"/><br/>
    	<input type="submit" value="提交"/>
    </form>
  </body>
</html>



apache 的fileupload 工具有bug 在某些操作系统上运行时,filename会包含路径


servlet 的线程安全

    servlet 存在线程安全问题

        容器收到一个请求 就会启动一个线程来处理该请求

        容器在默认情况下,对于某个servlet类型,只会创建一个实例

        当容器收到多个请求就会有多个线程同时访问某个servlet实例的情况,就有可能产生线程安全问题  多个线程同时修改servlet实例的属性

    解决方法:

    加锁 使用synchronized 对有线程安全问题的代码加锁

    让servlet 实现SingleThreadModel接口(不建议使用)容器会为servlet 创建多个实例(1个线程1个实例)因为有可能会产生过多的实例,影响性能




jsp 标签

 jstl     框架     自己的    公司的

jstl apache 开发的

    将标签对应的jar文件放到WEB-INF/lib下

    使用taglib指令导入标签

    taglib指令 <%@taglib uri="" prefix=""%>

    uri 指定命名空间  看.tld文件中 的<uri>

    prefix  命名空间的前缀

    核心标签 if choose forEach

    if  当test属性为true时,容器会执行标签体的内容

        test属性可以使用el表达式

    <c:if test="">

        标签体  可以是html 或者java 代码

     </c:if>


    <c:choose>

        <c:when test="">  when 分支

        </c:when>

        <c:when test="">

        </c:when>

        <c:when test="">

        </c:when>

        <c:otherwise>    全部不满足

        </c:otherwise>

    </c:choose>

    

    forEach  用来遍历集合

    items 属性指定要遍历的集合,可以使用el表达式来赋值

    var 属性指定绑定名称  绑定范围是pageContest 绑定值是集合中的一个对象

    varStatus 属性指定绑定名 绑定范围是pageContest 对应容器创建的对象  这个对象封装了当前迭代的状态  getIndex() 返回当前正在被迭代的对象的下标 从0 开始

        getCount() 返回当前被迭代的次数

    <c:forEach items="" var="" varStatus=""> 

    </c:forEach>

    

    一种用来代替jsp文件中java 代码的技术  容器在执行的时候,依据jsp标签可以找到对应的标签类,然后调用标签类中的代码    直接在jsp文件中写java代码,不利于jsp文件的维护


    容器根据标签的命名空间找到标签的描述文件.tld文件 然后依据标签的名称 找到标签类的名称 创建标签类的实例并调用相应的方法


    自定义标签

    写一个java类 继承SimpleTagSupport 类

    覆盖doTag,标签类的属性与标签的属性要一致,属性必须有set方法

    在doTag方法里面编写相应的处理逻辑

    描述标签,要在.tld文件里面描述,并将 .tld 文件放到web-inf 文件下

        body-content用来告诉容器,标签有没有标签体  如果有  可以出现哪些内容

        empty 没有标签体

     scriptless   可有标签体 但是 标签体的内容不能出现java代码 (<%%>)

    JSP    有标签体 标签体的内容可以重新啊java 代码

复杂标签技术才能支持JSP

简单标签技术只支持empty和scriptless

    


el表达式


<%@ page isELIgnored="false" %> 

不能使用 就在jsp中添加


    一套简单的计算规则,用于给jsp标签的属性赋值,也可以脱离jsp标签,直接运行

  访问bean的属性

    ${user.name}   两个相等   ${user["name"]}这个[]里面可以是绑定名也可以出现下标给数组访问

    容器会依次从pageContext,request,session,application 中查找(getAttribut)绑定名为"user"的对象,  找到后就不再向后找,调用对象个getName(),然后输出

    会将 null 转换为空字符串 如果找不到对应的对象,会输出空字符串

    如果需要制定查找范围可以使用 pageScope requestScope sessionScope,applicationScope

    ${sessionScope.user.name}

进行简单的计算 

    算术运算,+ - * / %  +在这里只是求和 

    关系运算 > >= < <= == !=

    逻辑运算 && || !

    empty运算 字符串是否为空 集合是否为空  空字符串 空集合 null 找不到值


获取 url中 参数

${param.name} 等价于 request.getParameter("name");

${paramValues.name}等价于 request.getParameterValues("name");

 


ajax

    用来改善用户体验的技术,利用浏览器内部的一个特殊的对象 XMLHttpRequest对象想服务器发请求 在发请求的时候浏览器不会销毁当前页面,用户还是可以对当前页面做其他的任何操作 ,服务器返回部分数据  不是一个完整的页面  在浏览器端,利用服务器返回的这些数据更新当前的页面  整个过程页面不刷新  标准化的技术  不需要下载插件 


    IE和非IE有不同的获取方式



1    onreadystatechange    绑定事件处理函数 处理 readystatechange事件  当 readyState 发生改变 就会产生 readyStatechange事件

    

2    resposeText  获得服务器返回的文本

3    responseXML 获得服务器返回的xml文档

4    status 获得服务器返回的状态码

5    readyState  表示 ajax对象和服务器进行通信的状态 有5个值 0,1,2,3,4

    4表示 ajax对象已经获取了服务器返回的所有的数据




获得ajax 对象

function getXhr(){
	var xhr = null;
	if(window.XMLHttpRequest){
		xhr = new XMLHttpRequest();
	}else{
		xhr = new ActiveXObjext('MicroSoft.XMLHttp');
	}
	return xhr;
	
var xhr =getXhr();


发请求get post 都可以

get 

    xhr.open('get','check_username.do?username=tom',true);

    true:发送异步请求  大部分的时候使用true

    false:发送同步请求  发送同步请求时, 浏览器会锁定当前页面,用户不能对当前页面进行其他的操作

    绑定一个事件处理函数

    xhr.onreadystatechange=f1;

    send 方法会将请求数据包发送出去

    xhr.send(null);//get 使用null     


post


服务端的处理逻辑  一般只需要返回部分的数据


事件处理函数  处理服务器返回的数据

function f1(){

// 只用 readyState 等于4 才能获得服务器返回的所有数据

if(xhr.readState == 4){

    var txt = xhr.responseText;

    dom 操作

}

}



编码 


    发送get请求    ie浏览器对应的ajax对象对中文参数值会使用gbk进行编码 其他的浏览器会使用utf-8编码  web服务器默认使用 iso8859-1解码  这样就出现了乱码

是用encodeURI函数对请求地址进行编码该函数会对其中的中文参数值按照utf-8进行编码


或者 tomcat    server.xml

Connector 中  添加一个

  URIEncoding="utf-8"



post 请求

xhr.open('post','check_username.do',true);

//添加一个content-type 消息头

xhr.setRequestHeader('content-type','appliction/x-www-form-urlencoded');

xhr.onreadystatechange=f1;

xhr.send('username=lmdtx&age=18');


编码

 所有浏览器 对应的ajax 对象对中文参数都使用utf-8进行解码  服务器使用 iso-8859-1解码  so   会有乱码 

request.setCharacterEncoding(utf-8);



json

javascript object notation

是一个轻量级的数据交换标准

 将数据转换成一种与平台无关的数据格式并传递给接收方



{属性名1:属性值1,属性名2:属性值2}

属性名必须要用引号

属性值 可以是 number string boolean null object   

数组 [{},{},{}]


使用json 编写  ajax应用

先将 java 对象转换成json 字符串  使用 json 提供的工具    JSONObjec  JSONArray


将json 字符串 转换为 javascript 对象  使用js框架提供额函数  

prototype 框架  提供的evalJSON函数

$(id)  document.getElementById(id)

$F(id) $(id).value

$(id1,id2,id3);  分别查找id 为id1 id2 id3 的节点  返回一个由这些节点组成的数组

strip() 除掉字符串两端的空格  和trim  一样

evalJSON  将json 字符串转换成相应的js对象或者js对象组成的数组

jQuery  框架  


当ajax 对象 想服务器发请求时, 浏览器会锁定当前页面,用户不能对当期页面做其他的操作


同步异步

 同步请求  浏览器会等待服务的响应  浏览器不会向下执行

在open(请求方式,请求地址,false);  发送同步请求


jQuery 基础

  jQuery 是一个js框架 最大的特点是 利用 选择器查找到操作的节点,并且将找到的节点封装成一个jQuery对象。 这样封装的好处有两个   一个是可兼容不同的浏览器   代码也会变得简洁


利用 选择器(jQ 借鉴了css选择器的语法) 查找到要操作的dom节点   这些节点会被封装成一个jQ对象   调用jQ对象的属性或者方法  jQ对象与dom对象的转换

dom对象-》jQ对象   $(dom对象)

jQ对象-》dom对象   $obj.get(0);    或者 $obj.get()[0];



选择器 :

     基本选择器:

    #id -》  根据id

    .class    根据 class

    element    根据元素

    select1,select2..selectn 根据多个

    *    所有

 

<!DOCTYPE html>
<html>
  <head>
    <title>s1.html</title>
	
    <meta name="keywords" content="keyword1,keyword2,keyword3">
    <meta name="description" content="this is my page">
    <meta name="content-type" content="text/html; charset=UTF-8">
    
    <!--<link rel="stylesheet" type="text/css" href="./styles.css">-->
	<script type="text/javascript" src="../js/jquery-1.11.1.js"></script>
  	<script type="text/javascript">
  		function f1() {
			$('#d1').css('font-size','100px');
		}
		function f2(){
			$('.s1').css('font-size','200px');
		}		
		function f3(){
			$('div').css('font-size','200px');
		}
		function f4(){
			$('#d1,p').css('font-size','200px');
		}
		function f5(){
			$('*').css('font-size','200px');
		}
  	</script>
  </head>
  
  <body>
  <div id="d1">this id </div>
  <div class="s1">this class</div>
  <p class="s1">this class</p>
  <input type="button" value="1" οnclick="f1()"/>
  <input type="button" value="2" οnclick="f2()"/>
  <input type="button" value="3" οnclick="f3()"/>
  <input type="button" value="4" οnclick="f4()"/>
  <input type="button" value="5" οnclick="f5()"/>
  </body>
</html>

 

层次选择器 selector


select1 select2  select1  下的 所有 select2节点

select1>select2    select1  子节点中 是 select2 的节点

select1+select2    找到select1 的下一个满足条件的节点

select1~select2    找到select1 后面的所有满足条件的节点

  

过滤选择器


    基本过滤选择器

    :first     第一个

    :last    最后一行

    :not(selector) 反选

    :even 偶数行

    :odd 奇数行

    :eq(index) 等于

    :gt(index) 大于

    :lt(index) 小于



内容过滤选择器

:contains(text) 匹配包含给定文本的元素

:empty 匹配所有不包含子元素或者文本的空元素

:has(selector) 匹配含有选择器所匹配的元素中有selector 的元素

:parent 匹配含有子元素或者文本的元素


可见性过滤选择器

:hidden 匹配所有不可见元素

或者type为hidden的元素

:visible 匹配所有的可见元素


属性过滤选择器

[attribute]  属性是

[attribute=value] 属性的值是

[attribute!=value] 属性的值不是


子元素过滤选择器

:nth-child(index/even/odd)


表单对象属性过滤选择器

:enabled

:disabled

:checked

:selected


表单选择器

:input

:text

:pasword

:radio

:checkbox

:submit

:image

:reset

:button

:file

:hidden

<!DOCTYPE html>
<html>
<head>
<title>1.html</title>
<meta name="keywords" content="keyword1,keyword2,keyword3">
<meta name="description" content="this is my page">
<meta name="content-type" content="text/html; charset=UTF-8">
<script type="text/javascript" src="js/jquery-1.11.1.js"></script>
<script type="text/javascript">
        function f1(){
            $('#t1 tbody tr:even').css('background-color','red');
            $('#t1 tbody tr:odd').css('background-color','yellow');
        }
        function f2(){
            $('tbody tr:contains(4)').css('background-color','#005500');
        }
        function f3(){
            $('#t1 tbody tr:eq(1) td:eq(1)').css('background-color','#550055');
            
        }
        
    </script>
</head>

<body οnlοad="f1();" style="font-size:30px;">
    员工信息
    <table  id = "t1" cellpadding="0" cellspacing="0" width="60%" border="1">
        <thead><tr><td>name</td><td>salary</td><td>age</td></tr></thead>
        <tbody> <tr><td>1</td><td>100</td><td>100</td></tr></tbody>
        <tbody> <tr><td>2</td><td>200</td><td>100</td></tr></tbody>
        <tbody> <tr><td>3</td><td>300</td><td>100</td></tr></tbody>
        <tbody> <tr><td>4</td><td>400</td><td>100</td></tr></tbody>
        <tbody> <tr><td>5</td><td>500</td><td>100</td></tr></tbody>
    </table>
    <input type="button" value="2" οnclick="f2();"/> 
    <input type="button" value="3" οnclick="f3();"/> 

</body>
</html>

dom 操作

1查询

    利用选择器找到节点之后 可以获取节点的html内容,文本内容属性值 value值

    html()  innerHTML 包含节点之间的所有内容

    text() innerText 只有文本

    attr() 访问某个属性

    val()  value 属性值

    也可以修改

2创建

$(html)


3插入节点

append(); 作为最后一个孩子

prepend() 在每个匹配的元素之后插入内容

after() 在每个匹配的元素之后插入内容

before()在每个匹配的元素之前插入内容


4删除节点

remove()

remove(selector)

empty() 清空节点


5数据与行为分离

将javascript代码写到 .js 文件里面, 然后在html 文件中引入相应的js文件方便维护

$(fn);

fn是一个函数  常用 匿名函数 

$(function(){

    //当整个页面加载完毕后。就会执行这里的代码

});


复制节点

clone()

clone(true) 是复制的节点也具有行为  将事件处理代码一块复制



属性操作

读取 attr('')

设置 attr('','')

设置多个 attr({"class":"s1","style":"color:red"});

删除removeAttr('')


样式操作

获取和设置attr("class","")

追加addClass('')

是否含有hasClass('')

移除 removeClass('')     removeClass('s1 s2')     removeClass()//删除所有

切换样式toggleClass  有这个就删除,没有就添加


遍历节点

children()  只考虑子元素,不考虑其他后代元素  () 中可以添加选择器

next() 下一个

prev() 上一个

siblings() 其他的兄弟

find(expr) 查找

parent() 遍历














mvc


模型封装业务逻辑  加工数据

视图表示逻辑展现数据

控制器协调 模型和视图  视图 向控制器发请求  由控制器调用相应的模型来处理,模型返回的处理结果也要给控制器 有控制器选择合适的视图来展现


模型:java类

视图:jsp 或者 模板

控制器:servlet 或者filter

  模型复用  维护 方便测试 

    增加难度 代码量加大