1 JSP
-
- JSP概念
JSP全名为Java Server Pages,中文名叫java服务器页面,其根本是一个简化的Servlet设计,它 [1] 是由Sun Microsystems公司倡导、许多公司参与一起建立的一种动态网页技术标准。JSP技术有点类似ASP技术,它是在传统的网页HTML(标准通用标记语言的子集)文件(*.htm,*.html)中插入Java程序段(Scriptlet)和JSP标记(tag),从而形成JSP文件,后缀名为(*.jsp)。 用JSP开发的Web应用是跨平台的,既能在Linux下运行,也能在其他操作系统上运行。
它实现了Html语法中的java扩展(以 <%, %>形式)。JSP与Servlet一样,是在服务器端执行的。通常返回给客户端的就是一个HTML文本,因此客户端只要有浏览器就能浏览。
JSP技术使用Java编程语言编写类XML的tags和scriptlets,来封装产生动态网页的处理逻辑。网页还能通过tags和scriptlets访问存在于服务端的资源的应用逻辑。JSP将网页逻辑与网页设计的显示分离,支持可重用的基于组件的设计,使基于Web的应用程序的开发变得迅速和容易。 JSP(JavaServer Pages)是一种动态页面技术,它的主要目的是将表示逻辑从Servlet中分离出来。
Java Servlet是JSP的技术基础,而且大型的Web应用程序的开发需要Java Servlet和JSP配合才能完成。JSP具备了Java技术的简单易用,完全的面向对象,具有平台无关性且安全可靠,主要面向因特网的所有特点。
-
- JSP的组成
[1]创建一个JSP
①
在webContent目录下右键-新建-jspFile。
②将一个HTML文件修改为JSP文件
把HTML文件打开 --
在HTML文件的第一行添加一个JSP的指令
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
把HTML文件的后缀修改为jsp
完事!
[2]JSP的组成
①指令 <%@ xxxx %> JSP页面一共有三大指令(page,incloud,taglib)
*Page 是指令名称.
*Language 此页面使用的脚本语言。目前为止JSP的动态脚本只有java。
ContentType 配置页面的内容类型
pageEncoding 配置页面的编码
import 配置页面应该导入的java包。
。。。。其他属性用到再说。
Page指令就是标明此页面为一个JSP页面,其中的属性配置了页面的相关配置
②静态内容
③小脚本 <% java code %>
④表达式 <%=表达式/变量 %>
表达式的作用是将表达式的结果输出到页面上。
⑤JSP注释 <%-- JSP的注释 --%>
JSP的注释仅仅存在于JSP页面的源代码中,在翻译,和编译之后的程序中都是不存在的,更不可能存在于运行过程。所以在JSP页面尽量使用JSP注释。
⑥申明 <%! 申明成员变量或者方法 %>
测试在JSP小脚本中申明方法:
小脚本中无法申明方法。
通过申明<%! %>申明方法:
⑦JSP动作 <jsp:activeName >
[3]使用JSP动态生成一个列表页面
①创建实体类
public class User { private int id; private String name; private int age; private int gender; //set和get方法省略 } |
②添加JSP页面 userList.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ page import="java.util.*,com.igeek.webcore.pojo.*" %> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>用户列表</title> <!-- boostrap需要的所有的css --> <link rel='stylesheet' type='text/css' href='js/bootstrap-3.3.7-dist/css/bootstrap.min.css'> <!-- 主题CSS --> <link rel='stylesheet' type='text/css' href='js/bootstrap-3.3.7-dist/css/bootstrap-theme.min.css'> <script type='text/javascript' src='js/jquery-2.1.0.min.js'></script> <script type='text/javascript' src='js/bootstrap-3.3.7-dist/js/bootstrap.min.js'></script> </head> <% //创建一个用户列表 List<User> users = new ArrayList<User>(); users.add(new User(1,"张三丰",18,1)); users.add(new User(2,"卡卡西",18,2)); users.add(new User(3,"卡卡东",18,2)); users.add(new User(4,"雷锋",18,1)); users.add(new User(5,"路飞",18,1)); %> <body> <table class="table"> <tr> <th>#</th> <th>姓名</th> <th>性别</th> <th>年龄</th> <th>操作</th> </tr> <% for(int i = 0;i<users.size();i++){ User u = users.get(i); %> <tr> <td><%=u.getId() %></td><td><%=u.getName() %></td> <td><%=u.getAge() %></td><td><%=u.getGender()==1?"男":"女" %></td> <td> <a href="inputEdit?userId=<%=u.getId() %>">编辑</a>/ <a href="javascript:delete(<%=u.getId() %>)">删除</a> </td> </tr> <%} %> </table> </body> </html> |
测试效果:
1.3JSP的执行过程
[1]JSP是服务器端的页面,是否可以像HTML一样通过浏览器执行。
Java代码实际上没有被发送到客户端。原因是浏览器根本就无法解释运行java代码。所以浏览器根本不可能直接运行jsp。
[2]JSP被翻译成java文件
在tomcat的work目录中查找JSP生成的java文件
Login.jsp生成的java文件的申明
再观察:
发现:编写的JSP文件生成的java代码继承了HttpJspBase,而HttpJspBase继承HttpSerlvet。也就是说我们编写JSP生成的java文件就是一个servlet。
结论:JSP文件最终会被tomcat翻译成servlet。然后在编译servlet,再运行。
[3]JSP中的组成部分被翻译成java代码后的内容
在生成的代码中有方法:相当于HttpServlet中的service方法
- 静态内容被输出
- Java小脚本 不做任何翻译。
- 表达式会使用out.print输出
- JSP的注释,不做任何翻译,也不会出现在java代码中。
- 申明 <%! %> 会被翻译成成员变量或者方法
为什么不能在小脚本中申明方法?
因为小脚本的程序最终会被放在_jspService方法内部,在方法内部当然不能再申明方法。
- JSP动作, 会调用专门的程序实现动作。
- JSP指令 会根据不同的指令进行不同的处理
1.4JSP可以配置在web.xml文件中
由于JSP最终也是被翻译成servlet所以JSP可以代替servlet,在web.xml文件中配置。
将servlet-class使用jspfile代替配置JSP的位置。
实际可能产生的情况:
通常情况下我们会将JSP放在WEB-INF中
访问:404
WEB-INF 和 META-INF目录下的任何内容都不能直接方法。
在web.xml文件中配置访问该JSP的url
测试:
- JSP内置对象
2.1什么是内置对象
所谓JSP的内置对象就类似于JS的内置对象window一样,不需要申明,不需要创建,就可以直接在页面中使用。比如:
修改login.jsp中的form的action
添加object.jsp,在 jsp中通过request获取请求参数
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>JSP内置对象</title> </head> <body> <% //通过request获取请求参数 String uname = request.getParameter("uname"); String upass = request.getParameter("upass"); %> 用户名:<%=uname %><br/> 密码:<%=upass %> </body> </html> |
测试结果:
在这个案例中object.jsp中的代码中的request对象没有申明,没有创建,就可以直接使用
request就是内置对象。
看内幕:在JSP页面的申明中request是不能直接使用。
查看JSP生产的源代码:
我们在小脚本中编写所有的java代码最终都会被翻译到_jspService方法中,而此方法的申明是:
所有的内置对象都是在_jspService方法的开始就申明好了,所以可以直接使用。
可是这里只有8个内置对象,还有一个呢?
还有一个是exception对象,只有将页面配置为错误页面时,才有此对象:
Error.jsp生成的java代码:
2.2九大内置对象
[1]request对象
Request对象是service的方法的参数。封装了所有的请求信息。
请求JSP就相当于请求了servlet,所以和servlet中的request是一个意思。
获取请求参数
和请求参数相关的API不再多说。
GetRequestURI();获取请求的uri
[2]response对象
response对象是service的方法的参数。提供了各种响应客户端的API。
设置响应头。
获取响应的流。
重定向。
[3]session对象
代表一个会话。
HTTP协议是无状态的。所谓状态就是不记录当前访问状态。也就是连续的刷新网页进行多次请求,服务器端并不知道是同一个客户端在请求。
实际你见过的状态都是被记录的。就是因为使用了session。
当客户单第一次请求服务器时,创建session,存储在服务器端,将sessionId返回给客户端。客户端进行第二次访问时会携带sessionId。服务器根据携带的sessionId找到对应的session。才能知道和上一次是同一客户端访问的。当浏览器关闭之后,浏览器缓存中的sessionId会消失,当再次访问时session会被重新创建。 当持续半小时(session的默认存活时间)没有对服务器进行访问时,服务器会销毁session。再访问时必须重新创建session。
Session的获取方式:
Session的类型是HttpSession。
[4]Application对象
Applicatiopn对象的类型是ServletContext
一个应用程序就只有一个application对象。在所有的页面中的application对象都是同一个对象。
[5] pageContext对象
pageContext对象的类型是:PageContext
此对象的主要作用就是获取其他内置对象
是page作用域中的操作对象
[6] config对象
Config对象的类型是ServletConfig
Config对象主要就是获取初始化参数。
配置初始化参数:
在页面获取:
[7]out对象
Out对象的类型是:JspWriter
jspWriter和PrintWriter是兄弟类。有同样的功能。
主要作用就是在网页中输出对应的数据。
主要API
Writ(..)
Print(..)
[8]page对象
Page对象的类型是Object
Page对象代表当前页面本身。
[9]exception对象
Exception对象的类型是Throwable。
此对象只有在page指令中的属性isErrorPage配置为true的时候才有该对象,该对象包含了所有的错误信息。
测试:
创建error.jsp
将page指令中的isErrorPage配置为true.
在页面可以使用exception对象输出错误信息。
将其他页面的page指令中的errorPage = “error.jsp”
当其他页面出错时就会进入error.jsp,并且将错误信息存储到exception对象中。
- JSP的4个作用域
Page < request < session <application
[1]page作用域
Page作用域中对应一个对象:pageContext。
pageContext中的和作用域相关的API
(1)给page作用设置加属性
pageContext.setAttribute(String key,Object value);
(2)获取page作用域中的属性值
pageContext.getAttribute(String key);
(3)删除page作用域中的属性值
pageContext.removeAttribute(String key);
所谓作用域就是相当于一个存储的空间。类似于map。可以存储各种类型数据。但是才空间只能在指定的范围内使用。
所谓page作用域就是page范围内的存储空间。 Page范围指的就是一个页面内。
比如:
<% //给page作用域设置一个属性 pageContext.setAttribute("pageAttr", "igeek-pageAttrValue"); %> <p>这里有很多代码,请脑补!</p> <% //获取page作用域中的属性值 Object pageAtrr = pageContext.getAttribute("pageAttr"); //输出 out.print(pageAtrr); //重新修改 pageContext.setAttribute("pageAttr", "igeek-pageAttrValue-update"); %> <p>这里有很多代码,请脑补!</p> <% //再获取page作用域中的属性值 pageAtrr = pageContext.getAttribute("pageAttr"); //输出 out.print(pageAtrr); //删除page作用域中的属性 pageContext.removeAttribute("pageAttr"); %> <p>这里有很多代码,请脑补!</p> <% //再获取page作用域中的属性值 pageAtrr = pageContext.getAttribute("pageAttr"); //输出 out.print(pageAtrr); %> |
页面效果:
Tips:在A页面中设置的属性,在B页面时无法获取的。
[2]request作用域
request作用域中对应一个对象:request。
request中的和作用域相关的API
(1)给page作用设置加属性
request.setAttribute(String key,Object value);
(2)获取page作用域中的属性值
request.getAttribute(String key);
(3)删除page作用域中的属性值
request.removeAttribute(String key);
request作用域中的对象request的操作作用域的API和pageContext是一样的,只是作用域的范围不一样。
Request作用域的意思是,一次请求中。
什么是一次请求?
客户端发送请求到服务器端响应完成称之为一次请求。
案例:
访问FirstServlet,执行了first和second两个servlet,响应客户端的是secondServlet的响应内容。 所以是一次请求,所以firstServlet和SecondServlet是共享request作用域中的数据的。
注意:这个案例中可以使用两个jsp或者jsp和servlet混合使用。
完全可以在serlvet中调用service读取数据,添加到request的作用域中,然后转发到jsp,再在jsp中从request作用域中取出显示。
4使用JSP和servlet完成一个简单的案例
[1]修改添加功能和登录功能
添加成功进入登录页面,添加失败返回添加页面,并且提示添加失败。
- 将添加的html修改为JSP
- 修改registServlet。
C.修改添加页面 可以显示错误提示信息
D.修改login.html为login.jsp
E.修改loginServlet实现登录失败是的提醒
F.修改登录页面,显示错误信息
[2]修改列表功能
A.添加一个accountList.jsp
在JSP中从request中取出用户列表信息,循环显示在页面上。
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ page import="com.igeek.pojo.*,java.util.*"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>账户列表</title> <!-- boostrap需要的所有的css --> <link rel='stylesheet' type='text/css' href='js/bootstrap-3.3.7-dist/css/bootstrap.min.css'> <!-- 主题CSS --> <link rel='stylesheet' type='text/css' href='js/bootstrap-3.3.7-dist/css/bootstrap-theme.min.css'> <script type='text/javascript' src='js/jquery-2.1.0.min.js'></script> <script type='text/javascript' src='js/bootstrap-3.3.7-dist/js/bootstrap.min.js'></script> <script type="text/javascript" src="js/ck/account.js"></script> </head> <body> <% //从request中取出数据 Object obj = request.getAttribute("accounts"); if (obj == null) { //重定向到accountList servlet response.sendRedirect("accountList"); return; } List<Account> accounts = (List<Account>) obj; %> <table class="table table-bordered"> <tr> <th>#</th> <th>账户名</th> <th>登录名</th> <th>电话</th> <th>邮箱</th> <th>创建时间</th> <th>操作</th> </tr> <% for(Account a :accounts){ %> <tr> <td><%=a.getAccountId() %></td> <td><%=a.getAccountName() %></td> <td><%=a.getLoginName() %></td> <td><%=a.getAccountTel() %></td> <td><%=a.getAccountEmail() %></td> <td><%=a.getCreateTime() %></td> <td> <A href="inputEdit?accountId=<%=a.getAccountId() %>">编辑</A>/ <A href="deleteAccount(<%=a.getAccountId() %>)">删除</A> </td> </tr> <%} %> </table> </body> </html> |
C.修改accountListServlet
package com.igeek.servlet;
import java.io.IOException; import java.io.PrintWriter; import java.util.List;
import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;
import com.igeek.pojo.Account; import com.igeek.service.AccountService;
/** * Servlet implementation class AccountListServlet */ public class AccountListServlet extends HttpServlet { private static final long serialVersionUID = 1L;
private AccountService accountService = new AccountService();
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //查询所有的账户,响应账户列表 List<Account> accounts = accountService.queryAll(); //将查询到的集合设置为request作用域的属性 request.setAttribute("accounts", accounts); //转发到accountList.jsp request.getRequestDispatcher("accountList.jsp").forward(request, response); }
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //调用自己的doGet方法。 无论是get请求还是post请求,都是同样的处理方式。 this.doGet(request, response); } } |
[3]修改编辑功能
A.添加一个编辑的jsp
在页面一开始的时候从request中取出要编辑的账户对象,然后将对象的数据通过value属性设置到对应的表单域中。
不要忘记添加一个隐藏域用来设置账户的编号。
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <%@ page import="com.igeek.pojo.*,java.util.*"%> <!DOCTYPE html> <html> <head> <meta charset='utf-8' /> <title>添加账户</title> <!-- boostrap需要的所有的css --> <link rel='stylesheet' type='text/css' href='js/bootstrap-3.3.7-dist/css/bootstrap.min.css'> <!-- 主题CSS --> <link rel='stylesheet' type='text/css' href='js/bootstrap-3.3.7-dist/css/bootstrap-theme.min.css'> <script type='text/javascript' src='js/jquery-2.1.0.min.js'></script> <script type='text/javascript' src='js/bootstrap-3.3.7-dist/js/bootstrap.min.js'></script>
</head> <body> <div style="text-align:center;"><h1 style="margin-left:auto;margin-right:auto;">编辑账户</h1></div> <% //从request中取出要编辑的账户对象 Object obj = request.getAttribute("editAccount"); if(obj==null){ //重定向到列表页面 response.sendRedirect("accountList"); return; } Account a = (Account)obj; //从request取出错误信息 Object errorMsg = request.getAttribute("editError"); //判断是否有错误信息 if(errorMsg!=null){ %> <div style="text-align:center; color:red"><%=errorMsg %></div> <%} %> <form class='form-horizontal' method='post' action='edit'> <input type="hidden" name="accountId" value="<%=a.getAccountId() %>"/> <div class='form-group'> <label for='inputEmail3' class='col-sm-2 control-label'>用户名</label> <div class='col-sm-10'> <input type='text' value="<%=a.getAccountName() %>" style='width: 500px;' class='form-control' name='username' placeholder='用户名' id='username'> <span style='display: none; color: red;' id='usernamespan'>*用户名不能为空</span> <span style='display: none; color: red;' id='namespan'>*用户名已存在</span> <!-- <input type='text' value='用户名不能为空' /> --> </div> </div> <div class='form-group'> <label for='inputEmail3' class='col-sm-2 control-label'>登录名</label> <div class='col-sm-10'> <input type='text' value="<%=a.getLoginName() %>" style='width: 500px;' class='form-control' name='loginName' placeholder='登录名' id='loginname'> <span style='display: none; color: red;' id='loginnamespan'>*登录名不能为空</span> </div> </div> <div class='form-group'> <label for='inputEmail3' class='col-sm-2 control-label'>密码</label> <div class='col-sm-10'> <input type='password' style='width: 500px;' class='form-control' name='password' placeholder='密码' id='password'> <span style='display: none; color: red;' id='passwordspan'>*密码必须由数字字母下划线组成</span> </div> </div> <div class='form-group'> <label for='inputEmail3' class='col-sm-2 control-label'>确认密码</label> <div class='col-sm-10'> <input type='password' style='width: 500px;' class='form-control' name='repassword' placeholder='确认密码' id='repassword'> <span style='display: none; color: red;' id='repasswordspan'>*两次输入的密码不一致</span> </div> </div> <div class='form-group'> <label for='inputPassword3' class='col-sm-2 control-label'>邮箱</label> <div class='col-sm-10'> <input type='email' value="<%=a.getAccountEmail() %>" style='width: 500px;' class='form-control' name='email' placeholder='邮箱' id='email'> <span style='display: none; color: red;' id='emailspan'>*请输入正确的邮箱格式</span> </div> </div> <div class='form-group'> <label for='inputPassword3' class='col-sm-2 control-label'>电话</label> <div class='col-sm-10'> <input type='text' value="<%=a.getAccountTel() %>" style='width: 500px;' class='form-control' name='tel' placeholder='电话' id='tel'> <span style='display: none; color: red;' id='telspan'>*请输入正确的电话格式</span> </div> </div> <div class='form-group'> <label class='col-sm-2 control-label'>性别</label> <input type='radio' <%=a.getAccountGender()==1?"checked":"" %> style='margin-left: 30px;' name='gender' value='1'>男 <input type='radio' style='margin-left: 30px;' <%=a.getAccountGender()==2?"checked":"" %> name='gender' value='2'>女 <input type='radio' style='margin-left: 30px;' name='gender' value='0' <%=a.getAccountGender()==0?"checked":"" %> >保密 </div> <div class='form-group'> <label for='inputPassword3' class='col-sm-2 control-label'>备注</label> <div class='col-sm-10'> <textarea class='form-control' style='width: 500px;' name='mark' placeholder='备注'><%=a.getAccountMark() %></textarea> </div> </div> <div class='form-group'> <div class='col-sm-offset-2 col-sm-10'> <div class='checkbox'> <label> <input type='checkbox'> Remember me </label> </div> </div> </div> <div class='form-group'> <div class='col-sm-offset-2 col-sm-10'> <button type='submit' class='btn btn-default' id='sub'>注册</button> </div> </div> </form> </body> </html>
|
B.修改inputEditServlet
package com.igeek.servlet;
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;
import com.igeek.pojo.Account; import com.igeek.service.AccountService;
/** * Servlet implementation class InputEditServlet */ public class InputEditServlet extends HttpServlet { private static final long serialVersionUID = 1L; private AccountService accountService = new AccountService(); protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //根据客户端传递的账户id查询账户信息 int accountId = 0; try { accountId = Integer.parseInt(request.getParameter("accountId")); } catch (NumberFormatException e) { } //查询account对象 Account a = accountService.queryById(accountId); //将查询的账户添加到request的作用域中 request.setAttribute("editAccount", a); //转发到编辑页面 request.getRequestDispatcher("editAccount.jsp").forward(request, response); }
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); }
} |