Jsp+servlet学习笔记
第一章:web开发入门
一、tomcat中start.bat启动一闪而过解决方法
在计算机环境变量中新建配置:
JAVA_HOME=C:\Program Files\Java\jdk1.6.0_10
JRE_HOME=C:\Program Files\Java\jre6
二、url、域名、主机名
url:http://www.sina.com
域名:sina.com
主机名:www.sina.com
一个域名下可以搭建多个主机名
mail.sina.com
三、web应用与虚拟目录的映射
1、项目直接放入webapps文件夹中
2、在server.xml文件中的host元素中放入
<Context debug="0" docBase="F:\workspace\NPCOms\WebRoot" path="/oms" reloadable="true" workDir="F:\tomcat5.5\work\NPCOms"></Context>,但需要重启tomcat服务器,path=""则设置为缺省
3、在F:\tomcat6.0\conf\Catalina\localhost目录下新建一个xx.xml文件,文件中配置
<Context debug="0" docBase="F:\workspace\xiangmu\WebRoot" reloadable="true" workDir="F:\tomcat6.0\work\xiangmu">
</Context>,不需重启服务器
xml文件的名字就是访问的项目名,可以a#b.xml实现多目录访问,即/a/b
如果文件名为root.xml,则项目为默认项目,即http://localhost:8080即可访问
四、查一个网站的ip
ping www.sina.com.cn
五、dns
1、我们输入域名时首先访问的是本机电脑上配置的dns文件,找不到再去网上的dns服务器上找
2、设置dns,打开C:\Windows\System32\drivers\etc目录下hosts文件,加入
192.168.0.100 www.huangzebiao.com
在tomcat中的server.xml中加入
<Host name="www.huangzebiao.com" appBase="F:\news">
<Context docBase="F:\news" path="/news" >
</Context>
</Host>
http://www.huangzebiao.com/news/1.htm即可访问到
六、web项目打包
1.用rar软件打包,选择zip格式,然后文件后缀名改为jar
2. jar -cvf servletDemo.jar servletDemo 把servletDemo文件夹中的内容(包括了该文件夹)打包成了servletDemo.jar文件
七、运行jar文件,在dos窗口下输入
javaw/java -jar xxx.jar
GUI使用javaw启动,控制台下的使用java。
第二章:servlet
一、Servlet的生命周期
Servlet对象是用户第一次访问时被创建,创建时调用init()方法进行初始化,此后Servlet对象会驻存在内存中,为以后的每次请求做响应;客户端的每次请求到达时,service()方法会被执行,service()方法自动派遣运行与请求对应的doXXX方法(doGet,doPost);当Servlet对象被摧毁时调用destroy()方法,即web服务器关闭时。
二、Servlet的一个简单示例
public class MyServlet extends GenericServlet {
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
res.getOutputStream().write("Servlet GenericServlet !!!".getBytes());
}
}
web.xml
<servlet>
<servlet-name>MyServlet</servlet-name>
<servlet-class>com.xunfang.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyServlet</servlet-name>
<url-pattern>/my</url-pattern>
</servlet-mapping>
三、Servlet接口的两个实现类:GenericServlet 和 HttpServlet(HttpServlet复写了service方法)
public class YourSer extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
res.getOutputStream().write("Servlet HttpServlet!!!".getBytes());
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request,response);
}
}
web.xml
<servlet>
<servlet-name>YourSer</servlet-name>
<servlet-class>com.xunfang.YourSer</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>YourSer</servlet-name>
<url-pattern>/you</url-pattern>
</servlet-mapping>
四、快捷键: Alt+ <-- 退后一步
五、改变发布到tomcat服务器上项目的名字
项目,右键properties->myeclipse->web->web context-root改下名字
六、servlet通配符
同一个Servlet可以被映射到多个URL上,即多个<servlet-mapping>元素的<servlet-name>子元素的设置值可以是同一个Servlet的注册名。
在Servlet映射到的URL中也可以使用*通配符,但是只能有两种固定的格式:一种格式是“*.扩展名”,另一种格式是以正斜杠(/)开头并以“/*”结尾。
<servlet-mapping>
<servlet-name>
AnyName
</servlet-name>
<url-pattern>
*.do
</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>
AnyName
</servlet-name>
<url-pattern>
/action/*
</url-pattern>
</servlet-mapping>
对于如下的一些映射关系:谁形式越像就映射哪个,如果*号在前优先级就低
Servlet1 映射到 /abc/*
Servlet2 映射到 /*
Servlet3 映射到 /abc
Servlet4 映射到 *.do
问题:
当请求URL为“/abc/a.html”,“/abc/*”和“/*”都匹配,哪个servlet响应:
Servlet引擎将调用Servlet1。
当请求URL为“/abc”时,“/abc/*”和“/abc”都匹配,哪个servlet响应:
Servlet引擎将调用Servlet3。
当请求URL为“/abc/a.do”时,“/abc/*”和“*.do”都匹配,哪个servlet响应:
Servlet引擎将调用Servlet1。
当请求URL为“/a.do”时,“/*”和“*.do”都匹配,哪个servlet响应:
Servlet引擎将调用Servlet2。
当请求URL为“/xxx/yyy/a.do”时,“/*”和“*.do”都匹配,哪个servlet响应:
Servlet引擎将调用Servlet2。
七、Servlet中的方法调用次数
Servlet是一个供其他Java程序(Servlet引擎)调用的Java类,它不能独立运行,它的运行完全由Servlet引擎来控制和调度。
针对客户端的多次Servlet请求,通常情况下,服务器只会创建一个Servlet实例对象,也就是说Servlet实例对象一旦创建,它就会驻留在内存中,为后续的其它请求服务,直至web容器退出,servlet实例对象才会销毁。
在Servlet的整个生命周期内,Servlet的init方法只被调用一次。而对一个Servlet的每次访问请求都导致Servlet引擎调用一次servlet的service方法。对于每次访问请求,Servlet引擎都会创建一个新的HttpServletRequest请求对象和一个新的HttpServletResponse响应对象,然后将这两个对象作为参数传递给它调用的Servlet的service()方法,service方法再根据请求方式分别调用doXXX方法。
假设有70个人,同时像一台服务器发送一个请求:servlet对象创建一个,init方法调用一次,service方法调用70次,request对象和response对象创建70个;
假设每个人发送10个请求:servlet对象创建一个,init方法调用一次,service方法调用700次,request对象和response对象创建700个;
八、服务器启动时就创建一个servlet对象
如果在<servlet>元素中配置了一个<load-on-startup>元素,那么WEB应用程序在启动时,就会装载并创建Servlet的实例对象、以及调用Servlet实例对象的init()方法。
举例:
<servlet>
<servlet-name>invoker</servlet-name>
<servlet-class>
org.apache.catalina.servlets.InvokerServlet
</servlet-class>
<load-on-startup>1</load-on-startup>数字越小越优先创建
</servlet>
用途:为web应用写一个InitServlet,这个servlet配置为启动时装载,为整个web应用创建必要的数据库表和数据。
九、缺省servlet
如果某个Servlet的映射路径仅仅为一个正斜杠(/),那么这个Servlet就成为当前Web应用程序的缺省Servlet。
凡是在web.xml文件中找不到匹配的<servlet-mapping>元素的URL,它们的访问请求都将交给缺省Servlet处理,也就是说,缺省Servlet用于处理所有其他Servlet都不处理的访问请求。
在<tomcat的安装目录>\conf\web.xml文件中,注册了一个名称为org.apache.catalina.servlets.DefaultServlet的Servlet,并将这个Servlet设置为了缺省Servlet。
当访问Tomcat服务器中的某个静态HTML文件和图片时,实际上是在访问这个缺省Servlet。
十、servlet线程安全
当多个客户端并发访问同一个Servlet时,web服务器会为每一个客户端的访问请求创建一个线程,并在这个线程上调用Servlet的service方法,因此service方法内如果访问了同一个资源的话,就有可能引发线程安全问题。
如果某个Servlet实现了SingleThreadModel接口,那么Servlet引擎将以单线程模式来调用其service方法。
SingleThreadModel接口中没有定义任何方法,只要在Servlet类的定义中增加实现SingleThreadModel接口的声明即可。
对于实现了SingleThreadModel接口的Servlet,Servlet引擎仍然支持对该Servlet的多线程并发访问,其采用的方式是产生多个Servlet实例对象,并发的每个线程分别调用一个独立的Servlet实例对象。
实现SingleThreadModel接口并不能真正解决Servlet的线程安全问题,因为Servlet引擎会创建多个Servlet实例对象,而真正意义上解决多线程安全问题是指一个Servlet实例对象被多个线程同时调用的问题。事实上,在Servlet API 2.4中,已经将SingleThreadModel标记为Deprecated(过时的)。
十一、ServletConfig对象:用于封装servlet配置信息
在Servlet的配置文件中,可以使用一个或多个<init-param>标签为servlet配置一些初始化参数
<servlet>
<servlet-name>TestSer</servlet-name>
<servlet-class>com.xunfang.TestSer</servlet-class>
<init-param>
<param-name>user</param-name>
<param-value>root</param-value>
</init-param>
<init-param>
<param-name>password</param-name>
<param-value>root</param-value>
</init-param>
</servlet>。
当servlet配置了初始化参数后,web容器在创建servlet实例对象时,会自动将这些初始化参数封装到ServletConfig对象中,并在调用servlet的init方法时,将ServletConfig对象传递给servlet。进而,程序员通过ServletConfig对象就可以得到当前servlet的初始化参数信息。
Enumeration e = this.getServletConfig().getInitParameterNames();
while(e.hasMoreElements()){
String name=(String) e.nextElement();
String value=this.getServletConfig().getInitParameter(name);
System.out.println(value);
}
十二、ServletContext对象:用于封装web项目配置信息
WEB容器在启动时,它会为每个WEB应用程序都创建一个对应的ServletContext对象,它代表当前web应用。
ServletContext对象被包含在ServletConfig对象中,开发人员在编写servlet时,可以通过 ServletContext sc = this.getServletContext();
ServletContext sc2 = this.getServletConfig().getServletContext();
方法获得对ServletContext对象的引用。
由于一个WEB应用中的所有Servlet共享同一个ServletContext对象,因此Servlet对象之间可以通过ServletContext对象来实现通讯。ServletContext对象通常也被称之为context域对象。
ServletContext应用:
多个Servlet通过ServletContext对象实现数据共享。
获取WEB应用的初始化参数。跟ServletConfig类似
实现Servlet的转发。一般不用这种来转发,使用request对象来转发
利用ServletContext对象读取资源文件:
得到文件路径
读取资源文件的方式
.properties文件(属性文件)
InputStream in = this.getServletContext().
getResourceAsStream("/WEB-INF/classes/db.properties");
Properties props = new Properties();
props.load(in);
Set<String> names = props.stringPropertyNames();
for(String name : names){
String value = props.getProperty(name);
System.out.println(name+"="+value);
}
String realPath = this.getServletContext().
getRealPath("/WEB-INF/classes/db.properties");
FileInputStream in = new FileInputStream(realPath);
如果读取资源文件的不是servlet的话,就要通过类装载器去读了
InputStream in = TestDao.class.getClassLoader().
getResourceAsStream("db.properties");//不是/WEB-INF/classes/db.properties
Properties props = new Properties();
props.load(in);
Set<String> names = props.stringPropertyNames();
for(String name : names){
String value = props.getProperty(name);
System.out.println(name+"="+value);
}
String path = TestDao.class.getClassLoader().
getResource("db.properties").getPath();
FileInputStream in = new FileInputStream(path);
十三、HttpServletResponse对象:用于封装响应信息
1、OutputStream中文乱码输出问题:
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setHeader("Content-type", "text/html;charset=utf-8");//控制浏览器以什么码表解析
String data = "中国";
OutputStream out=response.getOutputStream();
out.write(data.getBytes("utf-8"));//服务器以utf-8编码输出,浏览器就一定要以utf-8码表解析
}
2、PrintWriter 中文乱码输出问题:
response.setCharacterEncoding("utf-8");//服务器默认以iso8859-1输出,因此得改变,此行代码代表服务器以哪种码表响应
response.setHeader("Content-type", "text/html;charset=utf-8");//控制浏览器以什么码表解析
//response.setContentType("text/html;charset=utf-8");等价于上面一行,间接的把第一行也设置好了
String data = "中国";
PrintWriter out = response.getWriter();
out.write(data);
3、下载文件
String path = this.getServletContext().getRealPath("/download/1.jpg");//中文.jpg
String filename = path.substring(path.lastIndexOf("\\")+1);
response.setHeader("content-disposition", "attachment;filename="+filename);
//response.setHeader("content-disposition","attachment;filename="+URLEncoder.encode(filename, "utf-8"));//中文乱码文件解决
FileInputStream in = new FileInputStream(path);
OutputStream out = response.getOutputStream();
int len=0;
byte[] buf = new byte[1024];
while((len=in.read(buf))!=-1){
out.write(buf, 0, len);
}
out.close();
in.close();
4、java验证码在servlet中的实现
public class TestSer extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
HttpSession session = request.getSession();
BufferedImage image = new BufferedImage(120,25,BufferedImage.TYPE_INT_RGB);
//得到图像
Graphics g=image.getGraphics();
//设置背景
setBackGround(g);
//设置边框
setBloder(g);
//画随机线
drawRandomLine(g);
//画随机码,并将产生的随机码字符串返回存入session中,当做判断
String value = dramRandomNum((Graphics2D)g);
session.setAttribute("validateCode", value);
//响应类型
response.setContentType("image/jpeg");
//清楚缓存
response.setHeader("Pragma", "No-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", -1);
//把图像写到浏览器
ImageIO.write(image, "jpg", response.getOutputStream());
}
private String dramRandomNum(Graphics2D g) {
StringBuffer value=new StringBuffer();
g.setColor(Color.red);
g.setFont(new Font("宋体",Font.BOLD,20));
String base = "测试验证码基本常用字";
int x=5;
for(int i=0;i<4;i++){
int degree= new Random().nextInt()%30;//-30到30弧度的旋转
String ch = base.charAt(new Random().nextInt(base.length()))+"";
value.append(ch);
g.rotate(degree*Math.PI/180, x, 20);
g.drawString(ch, x, 20);
g.rotate(-degree*Math.PI/180, x, 20);
x+=30;
}
return value.toString();
}
private void drawRandomLine(Graphics g) {
g.setColor(Color.GREEN);
for(int i=0;i<5;i++){
int x1=new Random().nextInt(120);
int y1=new Random().nextInt(25);
int x2=new Random().nextInt(120);
int y2=new Random().nextInt(25);
g.drawLine(x1, y1, x2, y2);
}
}
private void setBloder(Graphics g) {
g.setColor(Color.BLUE);
g.drawRect(1, 1, 120-2, 25-2);
}
private void setBackGround(Graphics g) {
g.setColor(Color.WHITE);
g.fillRect(0, 0, 120, 25);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request,response);
}
}
页面引用:<img src="/servletDemo/test"/>
js实现验证码换一张:
function changeImage(img){
img.src=img.src+"?"+new Date().getTime();
}
<img src="/servletDemo/test" alt="换一张" coclick="changeImage(this)"/>
5、Java验证码在Struts2框架中的实现
public class ValidateCodeAction extends ActionSupport
{
HttpServletRequest request = this.ServletActionContext.getRequest();
HttpServletResponse response = this.ServletActionContext.getResponse();
HttpSession session = request.getSession();//struts2中ServletActionContext跟servlet中的ServletContext对象一样
//randomCode用于保存随机产生的验证码,以便用户登录后进行验证。
StringBuffer randomCode = new StringBuffer();
private static final long serialVersionUID = 1L;
//验证码图片的宽度。
private int width=60;
//验证码图片的高度。
private int height=20;
//验证码字符个数
private int codeCount=4;
private int x=0;
//字体高度
private int fontHeight;
private int codeY;
char[] codeSequence = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
public String execute() throws Exception {
response.setHeader("Pragma", "No-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
response.setHeader("Content-Type", "image/jpeg");
//图片宽高
int width = 95;
int height = 30;
BufferedImage bimage = null;
Graphics2D g = null;
HttpSession session = request.getSession();
OutputStream out = null;
String value;
try
{
out = response.getOutputStream();
bimage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Random rand=new Random(System.currentTimeMillis());
g = bimage.createGraphics();
// 设置随机背景色
Color color = new Color(rand.nextInt(255), rand.nextInt(255), rand.nextInt(255));
//Color color = new Color(7, 147,77);
// 填充深色背景
g.setColor(color.darker());
g.fillRect(0, 0, width, height);
// 设置字体
g.setFont(new Font("arial",Font.BOLD,36));
// 随机生成字符,根据截取的位数决定产生的数字
value = UUID.randomUUID().toString().replace("-","").substring(0,4);
int w = (g.getFontMetrics()).stringWidth(value);
int d = (g.getFontMetrics()).getDescent();
int a = (g.getFontMetrics()).getMaxAscent();
int x = 0, y =0;
// 设置随机线条,15这个数值越大图片中线条越稀蔬
for (int i = 0; i < height; i += 15)
{
g.setColor(new Color(rand.nextInt(255), rand.nextInt(255), rand.nextInt(255)));
g.drawLine(x, y + i, width, y+i);
}
// reset x and y
x=0;
y=0;
//设置随机线条,15这个数值越大图片中线条越稀蔬
for (int i = 0; i < height; i += 15)
{
g.setColor(new Color(rand.nextInt(255), rand.nextInt(255), rand.nextInt(255)));
g.drawLine(x, y + d - i, width + w, height + d - i);
}
//展示验证码中颜色,随机
g.setColor(new Color(rand.nextInt(255), rand.nextInt(255), rand.nextInt(255)).brighter());
// 设置文字出现位置为*
x = width/2 - w/2;
y = height/2 + a/2 - 6;
//文字变形设置
AffineTransform fontAT = new AffineTransform();
int xp = x-2;
// 每个文字都变形
for (int c=0;c<value.length();c++)
{
// 产生弧度
int rotate = rand.nextInt(20);
fontAT.rotate(rand.nextBoolean() ? Math.toRadians(rotate) : -Math.toRadians(rotate/2));
Font fx = new Font("arial", Font.BOLD, 36).deriveFont(fontAT);
g.setFont(fx);
//产生随机的颜色分量来构造颜色值,这样输出的每位数字的颜色值都将不同。
Random random = new Random();
int red = random.nextInt(255);
int green = random.nextInt(255);
int blue = random.nextInt(255);
//用随机产生的颜色将验证码绘制到图像中。
g.setColor(new Color(red, green, blue));
String ch = String.valueOf(value.charAt(c));
int ht = rand.nextInt(3);
// 打印字并移动位置
g.drawString(ch, xp, y + (rand.nextBoolean()?-ht:ht));
//移动指针.
xp+=g.getFontMetrics().stringWidth(ch) + 2;
}
// 打印出图片
ImageIO.write(bimage, "png", out);
//设置进当前会话
System.out.println(value);
session.setAttribute("validateCode", value);
}
catch (IOException ex)
{
ex.printStackTrace();
}
finally
{
if (g != null)
{
g.dispose();
}
if (out != null)
{
try
{
// 关闭OutputStream
out.close();
}
catch (IOException ex)
{
ex.printStackTrace();
}
}
}
return null;
// req.getRequestDispatcher("image.jsp").forward(req, resp);
}
}
6、控制浏览器定时刷新
String message="<meta http-equiv='refresh' content='3;url=/servletDemo/index.jsp'>登录成功,本浏览器将在3秒后跳转!";
this.getServletContext().setAttribute("message", message);
this.getServletContext().getRequestDispatcher("/message.jsp").forward(request, response);
message.jsp
<%
String message=(String)application.getAttribute("message");
out.write(message);
%>
7、请求重定向
response.sendRedirect("/servletDemo/index.jsp");
十四、HttpServletRequest对象:用于封装请求信息
1、Request常用方法
getRequestURL方法返回客户端发出请求时的完整URL。
getRequestURI方法返回请求行中的资源名部分。
getQueryString 方法返回请求行中的参数部分。
getPathInfo方法返回请求URL中的额外路径信息。额外路径信息是请求URL中的位于Servlet的路径之后和查询参数之前的内容,它以“/”开头。
getRemoteAddr方法返回发出请求的客户机的IP地址
getRemoteHost方法返回发出请求的客户机的完整主机名
getRemotePort方法返回客户机所使用的网络端口号
getLocalAddr方法返回WEB服务器的IP地址。
getLocalName方法返回WEB服务器的主机名
2、获得客户机请求头
getHeader方法
getHeaders方法
getHeaderNames方法
3、获得客户机请求参数(客户端提交的数据)
getParameter方法
String value = request.getParameter("username");
if(value!=null && !value.trim().equals("")){
System.out.println(value);
}
getParameterNames方法
Enumeration names = request.getParameterNames();
while(names.hasMoreElements()){
String name = (String)names.nextElement();
System.out.println(name+"="+request.getParameter(name));
}
getParameterValues(String name)方法
String[] values = request.getParameterValues("username");
for(int i=0;values!=null && i<values.length;i++){
System.out.println(values[i]);
}
getParameterMap方法:request.getParameterMap()返回的值,是一个Map类型的,记录着所提交的请求中请求参数和请求参数值的映射关系。request.getParameterMap()返回值使用泛型时应该是Map<String,String[]>形式,因为有时像checkbox这样的组件会有一个name对应对个value的时候,所以该Map中键值对是“String-->String[]”的实现。
Map<String,String[]> map = request.getParameterMap();
Iterator<Entry<String, String[]>> it = map.entrySet().iterator();
while(it.hasNext()){
Entry<String, String[]> en = it.next();
String name=en.getKey();
String[] values=en.getValue();
System.out.print(name+":");
for(int i=0;values!=null && i<values.length;i++){
System.out.print(values[i]+" ");
}
System.out.println();
}
4、request乱码问题
假设jsp页面是用utf-8编码
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
这样,当输入中文字符时,传递到tomcat服务器上是用了utf-8编码的数据,由于tomcat服务器默认用的是ISO8859-1码表来解码,因此会出现问题
解决方法(两种):
(1)改变tomcat服务器request解码方式(只对post提交方式有效)
request.setCharacterEncoding("utf-8");
String value = request.getParameter("username");
(2)把被服务器解码后的数据用服务器用的码表编码一次,得到浏览器编码后的数据,再重新用utf-8解码一次(通用方法)
String value = new String(request.getParameter("username").getBytes("ISO8859-1"),"utf-8");
若项目用的是gbk编码,则上面的都要改为gbk
5、request常见应用
(1)请求转发
String data = "中国";
request.setAttribute("data", data);
request.getRequestDispatcher("/message.jsp").forward(request, response);
请求转发的细节:
forward方法用于将请求转发到RequestDispatcher对象封装的资源。
如果在调用forward方法之前,在Servlet程序中写入的部分内容已经被真正地传送到了客户端,forward方法将抛出IllegalStateException异常。 如下
String data = "中国";
request.setAttribute("data", data);
if(true){
request.getRequestDispatcher("/index.jsp").forward(request, response);
//解决方法:在此加上 return; 语句,这样下面的代码就不会被执行
}
request.getRequestDispatcher("/message.jsp").forward(request, response);
(2)页面包含
request.getRequestDispatcher("/head.jsp").include(request, response);
6、web工程中各类地址的写法(重点)
重要原则:开始先写'/',然后看这资源是给谁用,如果是给服务器用,则'/'代表当前web工程,如果是给浏览器用,则代表网站(一个网站有多个web工程)
request.getRequestDispatcher("/index.jsp").forward(request, response);//是给服务器来转发的
response.sendRedirect("/servletDemo/index.jsp");//是给浏览器来重定向的
this.getServletContext().getRealPath("/index.jsp");//给服务器用
this.getServletContext().getResourceAsStream("/index.jsp");//给服务器用
/*
* <a href="/servletDemo/index.jsp">超链接</a>//给浏览器来跳转超链接的
*
* <form action="/servletDemo/index.jsp">//浏览器提交,给浏览器用的
*
* </form>
*/
十五、Cookie对象:Cookie是客户端技术,服务器把每个用户的数据以cookie的形式写给用户各自的浏览器。当用户使用浏览器再去访问服务器中的web资源时,就会带着各自的数据去。这样,web资源处理的就是用户各自的数据了。
1、javax.servlet.http.Cookie类用于创建一个Cookie,response接口也中定义了一个addCookie方法,它用于在其响应头中增加一个相应的Set-Cookie头字段。 同样,request接口中也定义了一个getCookies方法,它用于获取客户端提交的Cookie。
2、Cookie类的方法:
public Cookie(String name,String value)//构造一个Cookie
setValue与getValue方法 //设置和获取某个Cookie中的值
setMaxAge与getMaxAge方法 //设置和获取某个Cookie中的有戏期,以秒为单位
setPath与getPath方法//设置或获取某个Cookie的有效目录
getName方法 //获取某个Cookie的名称
3、案例:显示用户上次访问时间
//乱码问题
response.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
out.print("你上次访问时间为:");
Cookie[] cookies = request.getCookies();//获取到浏览器中的所有cookie
for(int i=0;cookies!=null&&i<cookies.length;i++){//遍历查找某个cookie
if(cookies[i].getName().equals("lastTime")){
long lastTime = Long.parseLong(cookies[i].getValue());
Date date = new Date(lastTime);
String formatDate = new SimpleDateFormat
("yyyy-MM-dd HH:mm:ss").format(date);
out.print(formatDate);
}
}
//创建一个cookie
Cookie cookie = new Cookie("lastTime",System.currentTimeMillis()+"");
//设置cookie的有效期,一定要设置,不然默认为浏览器一关闭就没了
cookie.setMaxAge(1*30*24*3600);
//设置有效目录,如下有效目录为/servletDemo
cookie.setPath("/servletDemo");
//通过response对象写入浏览器
response.addCookie(cookie);
4、cookie的细节
一个Cookie只能标识一种信息,它至少含有一个标识该信息的名称(NAME)和设置值(VALUE)。
一个WEB站点可以给一个WEB浏览器发送多个Cookie,一个WEB浏览器也可以存储多个WEB站点提供的Cookie。
浏览器一般只允许存放300个Cookie,每个站点最多存放20个Cookie,每个Cookie的大小限制为4KB。
如果创建了一个cookie,并将他发送到浏览器,默认情况下它是一个会话级别的cookie(即存储在浏览器的内存中),用户退出浏览器之后即被删除。若希望浏览器将该cookie存储在磁盘上,则需要使用maxAge,并给出一个以秒为单位的时间。将最大时效设为0则是命令浏览器删除该cookie。
注意,删除cookie时,path必须一致,否则不会删除
5、案例:显示上次浏览商品的实现
public class CookieDemo3 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
//输出所有商品
out.write("本站有如下商品:<br/>");
Map<String,Book>map=Db.getAll();
for(Map.Entry<String, Book> entry:map.entrySet()){
Book book=entry.getValue();
out.print("<a target=\"_blank\" href='/day07/servlet/cookieDemo4?id="
+book.getId()+"'>"+book.getName()+"</a><br/>");
}
//显示用户看过的商品
out.print("<br/>你曾经看过的商品<br/>");
Cookie cookies[]=request.getCookies();
for(int i=0;cookies!=null && i<cookies.length;i++){
if(cookies[i].getName().equals("bookHistory")){
String ids[]=cookies[i].getValue().split("\\,");//2,3,1
for(String id:ids){
Book book=(Book) Db.getAll().get(id);
out.print("<a target=\"_blank\" href='/day07/servlet/cookieDemo4?id="
+book.getId()+"'>"+book.getName()+"</a><br/>");
}
}
}
}
}
class Db{
private static Map<String,Book> map=new LinkedHashMap<String,Book>();
static {
map.put("1", new Book("1","JavaWeb开发","老k","一本好书"));
map.put("2", new Book("2","jdbc开发","老张","一本好书"));
map.put("3", new Book("3","spring开发","老li","一本好书"));
map.put("4", new Book("4","struts开发","老张","一本好书"));
map.put("5", new Book("5","android开发","老bi","一本好书"));
}
public static Map getAll(){
return map;
}
}
class Book{
private String id;
private String name;
private String author;
private String description;
public Book() {
super();
}
public Book(String id, String name, String author, String description) {
this.id = id;
this.name = name;
this.author = author;
this.description = description;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
//显示详细信息的servlet
public class CookieDemo4 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//根据用户带过来的id,显示相应的详细信息
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
String id=request.getParameter("id");
Book book=(Book)Db.getAll().get(id);
out.write(book.getId()+"<br/>");
out.write(book.getName()+"<br/>");
out.write(book.getAuthor()+"<br/>");
out.write(book.getDescription()+"<br/>");
//2.构建cookie,回写给浏览器;
String cookieValue=buildCookie(id,request);
Cookie cookie=new Cookie("bookHistory",cookieValue);
cookie.setMaxAge(1*30*24*3600);//1 个月
cookie.setPath("/day07");
response.addCookie(cookie);
}
private String buildCookie(String id, HttpServletRequest request) {
//bookHistory =null 1 1
//bookHistory=2,5,1 1 1,2,5
//bookHistory=2,5,4 1 1,2,5
//bookHistroy=2,5 1 1,2,5 // 假如列表最多3个
String bookHistroy=null;
Cookie cookies[]=request.getCookies();
for(int i=0;cookies!=null && i<cookies.length;i++){
if(cookies[i].getName().equals("bookHistory")){
bookHistroy=cookies[i].getValue();
}
}
if(bookHistroy==null)
return id;
//if(bookHistroy.contains(id))不能这样 21,23 也包括1
List<String> list=Arrays.asList(bookHistroy.split("\\,"));
LinkedList <String>linkedlist=new LinkedList<String>(list);
if(list.contains(id)){
linkedlist.remove(id);
linkedlist.addFirst(id);
}else{
if(list.size()>=3){
linkedlist.removeLast();
linkedlist.addFirst(id);
}else
linkedlist.addFirst(id);
}
StringBuffer sb=new StringBuffer();
for(String bid : linkedlist){
sb.append(bid+",");
}
return sb.deleteCharAt(sb.length()-1).toString();
}
}
十六、HttpSession对象:Session是服务器端技术,利用这个技术,服务器在运行时可以为每一个用户的浏览器创建一个其独享的session对象,由于session为用户浏览器独享,所以用户在访问服务器的web资源时,可以把各自的数据放在各自的session中,当用户再去访问服务器中的其它web资源时,其它web资源再从用户各自的session中取出数据为用户服务。
1、Session和Cookie的主要区别在于:
Cookie是把用户的数据写给用户的浏览器。
Session技术把用户的数据写到用户独占的session中。
Session对象由服务器创建,开发人员可以调用request对象的getSession方法得到session对象。
2、服务器是如何实现一个session为一个用户浏览器服务的:通过会写cookie的形式
3、session默认时间是30分钟,更改方式:
<session-config>
<session-timeout>60</session-timeout>//设置为60分钟
</session-config>
或:session.setMaxInactiveInterval(3600);//60分钟
4、session全部的摧毁:session.invalidate();
session某个的移除:session.removeAttribute(name);
5、解决买了多本书后,如果浏览器关闭,就在购物车找不到的问题:
浏览器一关闭,重新打开浏览器时创建的session就不是原先的那个了,因为他是基于cookie的,而cookie没有设置有效期,所以浏览器一关闭cookie就没了,所有就找不回原先的那个session了,所以解决方法是将session的sessionId号加入到cookie中
购买servlet:
HttpSession session=request.getSession();
session.setAttribute("name", "洗衣机");
String id=session.getId();
Cookie cookie=new Cookie("JSESSIONID",id);
cookie.setPath("/servletDemo");
cookie.setMaxAge(30*60);//30 minutes
response.addCookie(cookie);
结账servlet:
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=utf-8");
HttpSession session=request.getSession();
String name=(String) session.getAttribute("name");
PrintWriter out = response.getWriter();
if(name!=null)
out.write(name);
else
out.write("no buy");
6、session实现简单的购物
商品列表展示:
public class ListBookServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.print("本站有如下商品<br/>");
Map<String, Book> map = Db.getAll();
//request.getContextPath()->/servletDemo
for (Map.Entry<String, Book> entry : map.entrySet()) {
Book book = entry.getValue();
String str = "<a target=\"_blank\" href='"
+ request.getContextPath() + "/servlet/BuyServlet?id="
+ book.getId() + "'>" + book.getName() + "购买" + "</a><br/>";
out.print(str);
}
}
}
class Db {
private static Map<String, Book> map = new LinkedHashMap<String, Book>();
static {
map.put("1", new Book("1", "JavaWeb开发", "老k", "一本好书"));
map.put("2", new Book("2", "jdbc开发", "老张", "一本好书"));
map.put("3", new Book("3", "spring开发", "老li", "一本好书"));
map.put("4", new Book("4", "struts开发", "老张", "一本好书"));
map.put("5", new Book("5", "android开发", "老bi", "一本好书"));
}
public static Map getAll() {
return map;
}
}
class Book {
private String id;
private String name;
private String author;
private String description;
public Book() {
super();
}
public Book(String id, String name, String author, String description) {
this.id = id;
this.name = name;
this.author = author;
this.description = description;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
购买业务逻辑:
public class BuyServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("UTF-8");
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
String id = request.getParameter("id");
Book book = (Book) Db.getAll().get(id);
HttpSession session = request.getSession();
//解决浏览器一关闭session就找不到的问题
String sessionId = session.getId();
//cookie的name值一定要是"JSESSIONID",这才代表了session的Id
Cookie cookie = new Cookie("JSESSIONID",sessionId);
cookie.setMaxAge(30*60);
cookie.setPath("/servletDemo");
response.addCookie(cookie);
// 用session中得到用户购买的商品集合
List<Book> list = (List) session.getAttribute("list");
if (list == null) {
list = new LinkedList<Book>();
session.setAttribute("list", list);
}
list.add(book);
response.sendRedirect(request.getContextPath()
+ "/servlet/ListCartServlet");
}
}
购物车展示:
public class ListCartServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
//request.getSession(true):若存在会话则返回该会话,否则新建一个会话。
//request.getSession(false):若存在会话则返回该会话,否则返回null
HttpSession session = request.getSession(false);
if (session == null) {
out.write("您没有购买任何商品");
return;
}
List<Book> list = (List) session.getAttribute("list");
out.write("你购买了如下商品");
for (Book book : list) {
out.write(book.getName() + "<br/>");
}
}
}
7、利用session防表单重复提交
form.jsp
<script type="text/javascript">
function dosubmit(){
document.getElementById("tbn").disabled="disabled";
return true;
}
</script>
<form action="/servletDemo/servlet/DoFormServlet" method="post"
onsubmit="return dosubmit()">
用户名:<input type="text" name="username"/>
<input id="btn" type="submit" value="提交"/>
<input name="token" type="hidden" value="${token}"/>
</form>
FormServlet.java
public class FormServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 产生随机数(表单号)
TokenProcessor tp = TokenProcessor.getInstance();
String token = tp.generateToken();
request.getSession().setAttribute("token", token);
request.getRequestDispatcher("/form.jsp").forward(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
}
}
class TokenProcessor {// 令牌
private TokenProcessor() {
}
private static final TokenProcessor instance = new TokenProcessor();
public static TokenProcessor getInstance() {
return instance;
}
public String generateToken() {
String token = System.currentTimeMillis() + new Random().nextInt() + "";
try {
//通过java提供的MessageDigest 中的digest()将token转换为长度相同的摘要
MessageDigest md = MessageDigest.getInstance("md5");
byte[] md5 = md.digest(token.getBytes());
// 通过base64编码将摘要转换为人眼可识别的符号
BASE64Encoder encoder = new BASE64Encoder();
return encoder.encode(md5);
// return new String(md5);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
}
DoFormServlet.java
public class DoFormServlet extends HttpServlet {
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
boolean b = isTokenValid(request);
if(!b){
System.out.println("请不要重复提交");
return;
}
request.getSession().removeAttribute("token");
System.out.println("向数据库写用户名");
}
private boolean isTokenValid(HttpServletRequest request) {
String client_token = request.getParameter("token");
if(client_token==null){
return false;
}
String server_token=(String)request.getSession().getAttribute("token");
if(server_token==null){
return false;
}
if(!client_token.equals(server_token)){
return false;
}
return true;
}
}
8、
第三章:JSP
一、forward(转发)和redirect(重定向)的区别
forward:参数可以传过去,地址栏不变化
redirect:参数传不过去,地址栏发生变化
二、错误跳转
404.jsp页面要超过1K,才能做到。
三、jsp语法
1、JSP脚本表达式
<%= new java.util.Date() %>
2、JSP脚本片断
<%
int x = 10;
out.println(x);
%>
3、JSP声明
JSP页面中编写的所有代码,默认会翻译到servlet的service方法中, 而Jsp声明中的java代码被翻译到_jspService方法的外面。语法:
<%!
java代码
%>
所以,JSP声明可用于定义JSP页面转换成的Servlet程序的静态代码块、成员变量和方法 。
多个静态代码块、变量和函数可以定义在一个JSP声明中,也可以分别单独定义在多个JSP声明中。
JSP隐式对象的作用范围仅限于Servlet的_jspService方法,所以在JSP声明中不能使用这些隐式对象。
4、JSP注释
<%-- 注释信息 --%>
四、jsp的三个指令
JSP指令(directive)是为JSP引擎而设计的,它们并不直接产生任何可见输出,而只是告诉引擎如何处理JSP页面中的其余部分。在JSP 2.0规范*定义了三个指令:
page指令
Include指令
taglib指令
JSP指令的基本语法格式:<%@ 指令 属性名="值" %>
1、Page指令
page指令用于定义JSP页面的各种属性,无论page指令出现在JSP页面中的什么地方,它作用的都是整个JSP页面,为了保持程序的可读性和遵循良好的编程习惯,page指令最好是放在整个JSP页面的起始位置。
JSP 2.0规范中定义的page指令的完整语法:
<%@ page
[ language="java" ]
[ extends="package.class" ]
[ import="{package.class | package.*}, ..." ]
[ session="true | false" ]
[ buffer="none | 8kb | sizekb" ]
[ autoFlush="true | false" ]
[ isThreadSafe="true | false" ]
[ info="text" ]
[ errorPage="relative_url" ]
[ isErrorPage="true | false" ]
[ contentType="mimeType [ ;charset=characterSet ]" | "text/html ; charset=ISO-8859-1" ]
[ pageEncoding="characterSet | ISO-8859-1" ]
[ isELIgnored="true | false" ]
%>
2、include指令
include指令用于引入其它JSP页面,如果使用include指令引入了其它JSP页面,那么JSP引擎将把这两个JSP翻译成一个servlet。所以include指令引入通常也称之为静态引入。
语法:
<%@ include file="relativeURL"%>
其中的file属性用于指定被引入文件的相对路径。 file属性的设置值必须使用相对路径,如果以“/”开头,表示相对于当前WEB应用程序的根目录(注意不是站点根目录),否则,表示相对于当前文件。
细节:
被引入的文件必须遵循JSP语法。
被引入的文件可以使用任意的扩展名,即使其扩展名是html,JSP引擎也会按照处理jsp页面的方式处理它里面的内容,为了见明知意,JSP规范建议使用.jspf(JSP fragments)作为静态引入文件的扩展名。
由于使用include指令将会涉及到2个JSP页面,并会把2个JSP翻译成一个servlet,所以这2个JSP页面的指令不能冲突(除了pageEncoding和导包除外)。
3、taglib指令:Taglib指令用于在JSP页面中导入标签库
<%@ taglib prefix="tagPrefix" uri="URIToTagLibrary"%>
比如导入struts2标签:<%@ taglib prefix="s" uri="/struts-tags"%>
五、jsp的九个内置对象
request :HttpServletRequest
response :HttpServletResponse
session :HttpSession
application :ServletContext
config :ServletConfig
page :this
out :JspWriter -----> PrintWriter
exception
pageContext
1、out对象:用于向客户端发送文本数据。
out对象是通过调用pageContext对象的getOut方法返回的,其作用和用法与ServletResponse.getWriter方法返回的PrintWriter对象非常相似。
JSP页面中的out隐式对象的类型为JspWriter,JspWriter相当于一种带缓存功能的PrintWriter,设置JSP页面的page指令的buffer属性可以调整它的缓存大小,甚至关闭它的缓存。
只有向out对象中写入了内容,且满足如下任何一个条件时,out对象才去调用ServletResponse.getWriter方法,并通过该方法返回的PrintWriter对象将out对象的缓冲区中的内容真正写入到Servlet引擎提供的缓冲区中:
设置page指令的buffer属性关闭了out对象的缓存功能
out对象的缓冲区已满
整个JSP页面结束
同时使用out和response.getWriter()输出数据时,out的会后输出,所以应该统一用out来输出。
2、pageContext对象:pageContext对象是JSP技术中最重要的一个对象,它代表JSP页面的运行环境,这个对象不仅封装了对其它8大隐式对象的引用,它自身还是一个域对象,可以用来保存数据。并且,这个对象还封装了web开发中经常涉及到的一些常用操作,例如引入和跳转其它资源、检索其它域对象中的属性等
通过pageContext获得其他对象:
getException方法返回exception隐式对象
getPage方法返回page隐式对象
getRequest方法返回request隐式对象
getResponse方法返回response隐式对象
getServletConfig方法返回config隐式对象
getServletContext方法返回application隐式对象
getSession方法返回session隐式对象
getOut方法返回out隐式对象
pageContext作为域对象:
pageContext对象的方法
public void setAttribute(java.lang.String name,java.lang.Object value)
public java.lang.Object getAttribute(java.lang.String name)
public void removeAttribute(java.lang.String name)
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.APPLICATION_SCOPE
PageContext.SESSION_SCOPE
PageContext.REQUEST_SCOPE
PageContext.PAGE_SCOPE
findAttribute方法 (*重点,查找各个域中的属性)顺序为page,request,session,application,
相当于标签${data}
六、jsp的6个常用标签
1、<jsp:include>标签:用于把另外一个资源的输出内容插入进当前JSP页面的输出内容之中,这种在JSP页面执行时的引入方式称之为动态引入。
语法:
<jsp:include page="relativeURL | <%=expression%>" flush="true|false" />
page属性用于指定被引入资源的相对路径,它也可以通过执行一个表达式来获得。
flush属性指定在插入其他资源的输出内容时,是否先将当前JSP页面的已输出的内容刷新到客户端。
<jsp:include>与include指令的比较:
<jsp:include>标签是动态引入,<jsp:include>标签涉及到的2个JSP页面会被翻译成2个servlet,这2个servlet的内容在执行时进行合并。
而include指令是静态引入,涉及到的2个JSP页面会被翻译成一个servlet,其内容是在源文件级别进行合并。
不管是<jsp:include>标签,还是include指令,它们都会把两个JSP页面内容合并输出,所以这两个页面不要出现重复的HTML全局架构标签,否则输出给客户端的内容将会是一个格式混乱的HTML文档。
<jsp:include>标签:使用page属性指定被引入资源。
include指令:使用file属性指定被引入资源。
假设myweb应用的根目录下有一个a.jsp文件 如果将a.jsp页面映射成了如下地址:
http://localhost:8080/myweb/dir1/a.html
在a.jsp页面中使用了如下语句引入b.jsp文件:
<jsp:include page="b.jsp" />
请问:b.jsp要位于什么位置,上面的include才不会出错?
http://localhost:8080/myweb/b.jsp x
http://localhost:8080/myweb/dir1/b.jsp v
假设myweb应用程序的根目录下有一个a.jsp文件,如果将a.jsp页面映射为如下地址:
http://localhost:8080/myweb/dir1/a.html
在a.jsp页面中使用了如下语句引入b.jspf文件:
<%@ include file=“b.jspf”%>
请问: b.jspf要位于什么位置,上面的include才不会出错?
http://localhost:8080/myweb/b.jspf v
http://localhost:8080/myweb/dir1/b.jspf x
2、<jsp:forward>标签:用于把请求转发给另外一个资源。
语法:
<jsp:forward page="relativeURL | <%=expression%>" />
page属性用于指定请求转发到的资源的相对路径,它也可以通过执行一个表达式来获得。
3、<jsp:param>标签
当使用<jsp:include>和<jsp:forward>标签引入或将请求转发给其它资源时,可以使用<jsp:param>标签向这个资源传递参数。
语法1:
<jsp:include page="relativeURL | <%=expression%>">
<jsp:param name="parameterName" value="parameterValue|<%= expression %>" />
</jsp:include>
语法2:
<jsp:forward page="relativeURL | <%=expression%>">
<jsp:param name="parameterName" value="parameterValue|<%= expression %>" />
</jsp:include>
<jsp:param>标签的name属性用于指定参数名,value属性用于指定参数值。在<jsp:include>和<jsp:forward>标签中可以使用多个<jsp:param>标签来传递多个参数。
4、<jsp:useBean/>、<jsp:setProperty />、<jsp:getProperty />通常一起搭配使用
<%@ page import="com.xunfang.Person"%>
<jsp:useBean id="user" scope="page" class="com.xunfang.Person">//实例化一个对象,在此注意,如果要用到该标签,必须先把要示例化的对象先导入进来,如第一行代码
<jsp:setProperty name="user" property="age" value="24"/>//相当于调用set方法
</jsp:useBean>
<jsp:getProperty name="user" property="age" />//相当于调用get方法,在jsp页面中会直接输出值
七、映射JSP
<servlet>
<servlet-name>SimpleJspServlet</servlet-name>
<jsp-file>/simple.jsp</jsp-file>
</servlet>
……
<servlet-mapping>
<servlet-name>SimpleJspServlet</servlet-name>
<url-pattern>/xxx/yyy.html</url-pattern>
</servlet-mapping>
八、大数运算BigDecimal 类
BigDecimal a = new BigDecimal("100.232323232323231443");
BigDecimal b = new BigDecimal("14.232327676465663232323231443");
a.add(b).toString();//+
a.subtract(b).toString();//-
a.multiply(b).toString();//*
a.divide(b,2,BigDecimal.ROUND_HALF_UP);// / 保留数点后2位
第四章 EL表达式和jstl标签
一、EL表达式
1、${标识符},调用了pageContext.findAttribute()方法,依次从各个域中获取对象,如果不存在,则返回“”(不是返回null)
<%
String data="my data";
request.setAttribute("data",data);
%>
${data } <%--pageContext.findAttribute("data") page request session application --%>
<br/>
<%
Person p=new Person();
p.setName("namenamename");
request.setAttribute("p",p);
%>
${p.name }
<%
Person p1=new Person();
Address a=new Address();
a.setCity("huang gang");
p1.setAddress(a);
request.setAttribute("p1",p1);
%>
${p1.address.city }
<%
List list=new ArrayList();
list.add(new Address("上海"));
list.add(new Address("北京2"));
list.add(new Address("武汉"));
request.setAttribute("list",list);
%>
${list[1].city } <%--北京2 --%>
<%
Map map=new HashMap();
map.put("aa",new Address("上海"));
map.put("bb",new Address("北京2"));
map.put("cc",new Address("武汉"));
map.put("111",new Address("南京"));
request.setAttribute("map",map);
%>
${map.aa.city } <%--上海 --%>
${map["111"].city } <%--南京 ,通常用点号,点号取不出来用[]--%>
${pageContext.request.contextPath }<%--/servletDemo --%>
二、jstl标签库
1、使用步骤
(1)导入jstl.jar和standerd.jar两个jar包
(2)jsp页面头部引入<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%
List list=new ArrayList();
list.add(new Address("上海"));
list.add(new Address("北京2"));
list.add(new Address("武汉"));
request.setAttribute("list",list);
%>
<c:forEach var="a" items="${list}">
${a.city}
</c:forEach>
<%
Map map=new HashMap();
map.put("aa",new Address("上海"));
map.put("bb",new Address("北京2"));
map.put("cc",new Address("武汉"));
map.put("111",new Address("南京"));
request.setAttribute("map",map);
%>
<c:forEach var="b" items="${map }">
${b.key } : ${b.value.city } <br/>
</c:forEach>
<c:if test="${user!=null }">
欢迎
</c:if>
<c:if test="${user==null }">
请登录
</c:if>
第六章 java增强基础
一、junit4单元测试
public class TestCeshi {
@Before
public void before(){
System.out.println("before");
}
@Test
public void ceshi(){
Person p = new Person();
p.run();
}
@Test
public void ceshi2(){
Person p = new Person();
p.eat();
}
@After
public void after(){
System.out.println("after");
}
}
before
run
after
before
eat
After
public class TestCeshi {
@BeforeClass
public static void before(){
System.out.println("before");
}
@Test
public void ceshi(){
Person p = new Person();
p.run();
}
@Test
public void ceshi2(){
Person p = new Person();
p.eat();
}
@AfterClass
public static void after(){
System.out.println("after");
}
}
before
run
eat
after
二、枚举
public enum Enum1 {
A("100"),B("90"),C("80"),D("70"),E("60");
/* A,B,C,D,E;
private Enum1(){}
public static final Enum1 A = new Enum1();
public static final Enum1 B = new Enum1();
public static final Enum1 C = new Enum1();
public static final Enum1 D = new Enum1();
public static final Enum1 E = new Enum1();
A("100"),B("90"),C("80"),D("70"),E("60");
public static final Enum1 A = new Enum1("100");
public static final Enum1 B = new Enum1("90");
public static final Enum1 C = new Enum1("80");
public static final Enum1 D = new Enum1("70");
public static final Enum1 E = new Enum1("60");*/
private String value;
private Enum1(String value){
this.value=value;
}
public String getValue(){
return value;
}
}
@Test
public void test(){
System.out.println(Enum1.B.getValue());
}
三、枚举中的抽象方法
public enum Enum1 {
A("100"){
public String getAbstract(){
return "优";
}
},
B("90"){
public String getAbstract(){
return "良";
}
},
C("80"){
public String getAbstract(){
return "中";
}
},
D("70"){
public String getAbstract(){
return "及格";
}
},
E("60"){
public String getAbstract(){
return "不及格";
}
};
private String value;
private Enum1(String value){
this.value=value;
}
public abstract String getAbstract();
}
public enum Enum1 {
A{
public String getAbstract(){
return "优";
}
},
B{
public String getAbstract(){
return "良";
}
},
C{
public String getAbstract(){
return "中";
}
},
D{
public String getAbstract(){
return "及格";
}
},
E{
public String getAbstract(){
return "不及格";
}
};
public abstract String getAbstract();
}
四、Copy Qualified Name
选中Java源文件中的类名,然后鼠标右键->Copy Qualified Name,
得到的结构格式是包结构格式,如下:
com.npc.base.action.BaseAction
如果是在Package Explorer中选中Java源文件,然后鼠标右键->Copy Qualified Name,
得到的格式是路径格式,如下:
/NPCGPS/src/com/npc/base/action/BaseAction.java
五、上面是获得public,下面是获得其他的
clazz.getConstructor();//public
clazz.getMethod();
clazz.getField();
clazz.getDeclaredConstructor();//得到所有访问级别的
clazz.getDeclaredMethod();
clazz.getDeclaredField();
public class ConstructorDemo {
//public Person()
@Test
public void test1() throws Exception{
Class clazz=Class.forName("cn.itcast.reflect.Person");
Constructor c=clazz.getConstructor(null);
Person p=(Person) c.newInstance(null);//person
System.out.println(p.name);//xxx
}
//public Person(String name)
@Test
public void test2() throws Exception{
Class clazz=Class.forName("cn.itcast.reflect.Person");
Constructor c=clazz.getConstructor(String.class);
Person p=(Person) c.newInstance("abc");//person name
System.out.println(p.name);//abc
}
//public Person(String name,int password)
@Test
public void test3() throws Exception{
Class clazz=Class.forName("cn.itcast.reflect.Person");
Constructor c=clazz.getConstructor(String.class,int.class);
Person p=(Person) c.newInstance("abc",999);//person name password
System.out.println(p.name);//abc
}
//private Person(List list)
@Test
public void test4() throws Exception{
Class clazz=Class.forName("cn.itcast.reflect.Person");
Constructor c=clazz.getDeclaredConstructor(List.class);
c.setAccessible(true);
Person p=(Person) c.newInstance(new ArrayList());//list
System.out.println(p.name);//aaaa
}
@Test
public void test5() throws Exception{//相当于第一种
Class clazz=Class.forName("cn.itcast.reflect.Person");
Person p=(Person) clazz.newInstance();
System.out.println(p.name);//aaaa
}
}
public class MethodDemo{
// public void aa1()
@Test
public void test1() throws Exception{
Class clazz=Class.forName("cn.itcast.reflect.Person");
Method method=clazz.getMethod("aa1", null);
Person p=new Person();//person
method.invoke(p, null);//aa1
}
//public void aa1(String name,int password)
@Test
public void test2() throws Exception{
Class clazz=Class.forName("cn.itcast.reflect.Person");
Method method=clazz.getMethod("aa1", String.class,int.class);
Person p=new Person();//person
method.invoke(p, "xxxx",99);//name= xxxx password=99
}
//public Class[] aa1(String name,int[] password)
@Test
public void test3() throws Exception{
Class clazz=Class.forName("cn.itcast.reflect.Person");
Method method=clazz.getMethod("aa1", String.class,int[].class);
Person p=new Person();//person
Class cs[]=(Class[]) method.invoke(p, "xxxx",new int[]{1,2,3});//name= xxxx password=99
System.out.println(cs[0]);//class java.lang.String
}
//private void aa1(InputStream in)
@Test
public void test4() throws Exception{
Class clazz=Class.forName("cn.itcast.reflect.Person");
Method method=clazz.getDeclaredMethod("aa1",InputStream.class);
method.setAccessible(true);
Person p=new Person();//person
method.invoke(p,new FileInputStream("C:\\1.txt"));//
}
//public static void aa1(int num)
@Test
public void test5() throws Exception{
Class clazz=Class.forName("cn.itcast.reflect.Person");
Method method=clazz.getMethod("aa1",int.class);
method.invoke(null,777);//777
}
// public static void main(String []args){
@Test
public void test6() throws Exception{
Class clazz=Class.forName("cn.itcast.reflect.Person");
Method method=clazz.getMethod("main",String [].class);
//method.invoke(null,new String[]{"a","c"});//Wrong
//method.invoke(null,"a","c");//Wrong
String []str={"x","y","z"};
method.invoke(null, (Object)str);
method.invoke(null, new Object[]{new String[]{"a","c"} });
method.invoke(null, (Object)new String[]{"a","c"});
}
}
public class FieldDemo {
//public String name="aaaa";
@Test
public void test1() throws Exception{
Class clazz=Class.forName("cn.itcast.reflect.Person");
Field f=clazz.getField("name");
Person p=new Person();
Object value= f.get(p);
Class type=f.getType();
System.out.println(type);//class java.lang.String
if(type.equals(String.class)){
String S_value=(String)value;
System.out.println(S_value);//aaaa
}
f.set(p, "ppppp");
System.out.println(f.get(p));//ppppp
System.out.println(String.class);//class java.lang.String
}
//private int password;
@Test
public void test2() throws Exception{
Class clazz=Class.forName("cn.itcast.reflect.Person");
Field f=clazz.getDeclaredField("password");
f.setAccessible(true);
Person p=new Person();
f.set(p, 123);
System.out.println(f.get(p));//123
}
//private static int age=23;
@Test
public void test3() throws Exception{
Class clazz=Class.forName("cn.itcast.reflect.Person");
Field f=clazz.getDeclaredField("age");
f.setAccessible(true);
System.out.println(f.get(null));//23
}
}
public class Person {
public String name="xxx";
private int password;
private static int age=23;
public Person(){
System.out.println("person");
}
public Person(String name){
this.name=name;
System.out.println("person name");
}
public Person(String name,int password){
this.name=name;
System.out.println("person name password");
}
private Person(List list){
System.out.println("list");
}
public void aa1(){
System.out.println("aa1");
}
public void aa1(String name,int password){
System.out.println("name= "+name+" password="+password);
}
public Class[] aa1(String name,int[] password){
return new Class[]{String.class};
}
private void aa1(InputStream in){
System.out.println(in);
}
public static void aa1(int num){
System.out.println(num);
}
public static void main(String []args){
System.out.println("main");
}
}
六、内省
1、不借助开源jar包
public class Person {
private String name;
private String password;
private int age;
public void setAb(int a){
}
public String getName() {
return name;
}
public String getPassword() {
return password;
}
public int getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public void setPassword(String password) {
this.password = password;
}
public void setAge(int age) {
this.age = age;
}
}
public class Demo1 {
@Test
public void test1() throws IntrospectionException{//获取bean中所有属性
BeanInfo info=Introspector.getBeanInfo(Person.class);
BeanInfo info2=Introspector.getBeanInfo(Person.class,Object.class);
PropertyDescriptor[] pds=info.getPropertyDescriptors();
for(PropertyDescriptor pd:pds){
System.out.println(pd.getName());
//ab age class name password
}
}
@Test
public void test2() throws Exception{//对bean中的某个属性进行操作
Person p=new Person();
PropertyDescriptor pd=new PropertyDescriptor("age", Person.class);
Method method=pd.getWriteMethod();
method.invoke(p, 45);
System.out.println(p.getAge());//45
method=pd.getReadMethod();
System.out.println(method.invoke(p, null));//45
}
}
2、借助beanutils工具包
public class Person {
private String name;
private String password;
private int age;
private Date birthday;
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getName() {
return name;
}
public String getPassword() {
return password;
}
public int getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public void setPassword(String password) {
this.password = password;
}
public void setAge(int age) {
this.age = age;
}
}
public class Demo1 {
@Test
public void test1() throws Exception{
Person p=new Person();
BeanUtils.setProperty(p, "age", 456);
System.out.println(p.getAge());//456
}
@Test
public void test2() throws Exception{
String name="aaaa";
String age="123";
String password="pw";
Person p=new Person();
//只支持8种基本类型自动转换
BeanUtils.setProperty(p, "name", name);
BeanUtils.setProperty(p, "age", age);
BeanUtils.setProperty(p, "password", password);
System.out.println(p.getName());//aaaa
System.out.println(p.getAge());//123
System.out.println(p.getPassword());//pw
}
@Test
public void test3() throws Exception{
String birthday="1983-12-1";
//为了让日期赋值到bean的birthday属性上,给beanUtils注册一个日期转换器
//ConvertUtils.register(converter, clazz);
ConvertUtils.register(new Converter(){
public Object convert(Class type, Object value) {
if(value==null) return null;
if(!(value instanceof String)){
throw new ConversionException("只支持String类型的转换");
}
String str=(String)value;
if(str.trim().equals("")) return null;
SimpleDateFormat df=new SimpleDateFormat("yyyy-MM-dd",Locale.US);
try {
return df.parse(str);
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
}, Date.class);
Person p=new Person();
BeanUtils.setProperty(p, "birthday", birthday);
System.out.println(p.getBirthday());//pw
System.out.println("___"+BeanUtils.getProperty(p, "birthday"));
}
public void test5() throws Exception {
Map map=new HashMap();
map.put("name", "aaa");
map.put("password", "123");
map.put("brithday", "1980-09-09");
ConvertUtils.register(new DateLocaleConverter(), Date.class);//该注册器有缺陷
Person p=new Person();
//用map集合填充bean属性,map关键字和bean属性要一致
BeanUtils.populate(p, map);
}
}
七、泛型
1、自定义泛型方法:先写public void test1(T t),由于java中要先声明后使用,所以要在方法前面加上<T> ,即是public <T> T test1(T t)
public class Geric {
public <T> T test1(T t){
return t;
}
public <T,K> void test2(T t,K k){
}
}
2、自定义泛型类:在类定义了泛型后就不用在方法中再定义了,但静态方法还是要先定义
public class Geric<T> {
public T test1(T t){
return t;
}
public <K> void test2(T t,K k){
}
public static <T,K,E> void test3(T t,K k,E e){
}
}