目录
简介
JSP(Java Server Pages),简化的Servlet设计,在HTML标签中嵌套Java代码,用以高效开发Web应用的动态网页,是替换显示页面部分的Servlet(使用*.jsp文件替换XxxJSP.java)。
JSP和Servlrt:
JSP文件在容器中会转换成Servlet执行,JSP是对Servlet的一种高级封装,本质还是Servlet。但JSP可以很方便的编写或者修改HTML网页而不用去面对大量的println()语句。Tomcat会将xxx.jsp转换成Java代码,进而编译成.class文件运行,最终将运行结果通过response响应给客户端。
JSP脚本
脚本与脚本之间不可嵌套,脚本与HTML标签不可嵌套
声明脚本
格式:<%! 定义变量、函数 %>
-
声明脚本声明的变量是全局变量
-
声明脚本的内容必须在普通脚本<% %>中调用
-
如果声明脚本中的函数具有返回值,要使用输出脚本调用<%= %>
普通脚本
格式:<% Java代码 %>
普通脚本可以使用所有Java语法,除了定义函数
输出脚本
格式:<%= Java表达式 %>
-
输出脚本可以输出带有返回值的函数
-
输出脚本中不能加分号;
JSP注释
语法 | 描述 |
---|---|
<%-- 注释内容 --%> | JSP注释,注释内容不会被发送至浏览器甚至不会被编译 |
<!-- 注释内容 --> | HTML注释,通过浏览器查看网页源代码时可以看见注释内容 |
JSP指令
指令 | 描述 |
---|---|
<%@ page...%> | 定义页面的依赖属性,比如脚本语言、error页面、缓存需求等 |
<%@ include...%> | 包含其他文件 |
<%@ taglib...%> | 引入标签库的定义。可以是自定义标签 |
page指令
page指令为容器提供当前页面的使用说明。一个JSP页面可以包含多个page指令。
格式:<%@ page attribute1="value1" attribute2="value2" ... %>
include指令
通过include指令来包含其他文件,被包含的文件可以是JSP文件、HTML文件或文本文件。包含的文件就好像是当前JSP文件的一部分,会被同时编译执行(静态包含)。可能会有重名的冲突问题。不建议使用。
格式:<%@ include file="被包含的JSP路径" %>
tablib指令
引入JSP的标准签库
格式:<%@taglib uri="外部标签库路径" prefix="前缀" %>
动作标签
动作标签指的是JSP页面在运行期间的命令,语法:<jsp:action_name attribute="value" />
include
(1)<jsp:include>动作元素会将外部文件输出结果包含在JSP中(动态包含)
(2)语法:<jsp:include page="相对URL地址" />
(3)前面介绍过的include指令,它是将外部文件的输出代码复制到当前JSP文件中。这里的jsp:include动作不同,是将外部文件的输出结果引入到当前的JSP文件中
例:<jsp:include page="index.jsp"/>
useBean
(1)jsp:useBean 动作用来加载一个将在JSP页面中使用的JavaBean(创建一个指定类的对象)
(2)语法:<jsp:useBean id="name" class="package.className" />
(3)在类载入后,可以通过jsp:setProperty和jsp:getProperty动作来修改和获取bean的属性
例:
<jsp:useBean id="user" class="com.test.entity.User" />
setProperty
可以在jsp:useBean元素之后使用jsp:setProperty进行属性的赋值
属性 | 描述 |
---|---|
name | name属性是必需的。它表示要设置属性的是哪个Bean |
property | property属性是必需的。它表示要设置哪个属性 |
value | value属性是可选的。该属性用来指定Bean属性的值 |
例:<jsp:useBean id="user" class="com.test.entity.User" />
<jsp:setProperty name="user" property="name" value="zhangsan" />
getProperty
jsp:getProperty动作提取指定Bean属性的值,转换成字符串,然后输出在客户端
属性 | 描述 |
---|---|
name | 要检索的Bean属性名称、Bean必须已定义 |
property | 表示要提取Bean属性的值 |
例:<jsp:useBean id="user" class="com.test.entity.User" />
<jsp:setProperty name="user" property="name" value="zhangsan" />
forward
(1)jsp:forward动作把请求转到另外页面
(2)语法:<jsp:forward page="相对URL地址" />
例:<jsp:forward page="index.jsp" />
param
(1)在转发动作内部使用,做参数传递
(2)语法:<jsp:param name="" value="" />
例:
<jsp:forward page="index.jsp">
<!-- http请求参数传递-->
<jsp:param name="sex" value="nan" />
</jsp:forward>
内置对象
由JSP自动创建的对象,一共有9个,可以直接使用
对象名 | 类型 | 说明 |
---|---|---|
request | javax.servlet.http.HttpServletRequest | |
response | javax.servlet.http.HttpServletResponse | |
session | javax.servlet.http.HttpSession | 由session="true"开关 |
application | javax.servlet.ServletContext | |
config | javax.servlet.ServletConfig | |
exception | java.lang.Throwable | 由isErrorPage="false"开关 |
out | javax.servlet.jsp.JspWriter | javax.servlet.jsp.JspWriter |
pageContext | javax.servlet.jsp.PageContext | |
page | java.lang.Object当前对象this | 当前servlet实例 |
四大域对象
JSP有4大作用域对象,存储数据和获取数据的方式一样,不同的是取值的范围有差别。
-
pageContext(javax.servlet.jsp.PageContext)当前JSP页面范围
-
request(javax.servlet.http.HttpServletRequest)一次请求有效
-
session(javax.servlet.http.HttpSession)一次会话有效(关闭浏览器失效)
-
application(javax.servlet.ServletContext)整个Web应用有效(服务器重启或关闭失效)
EL表达式
用于替换作用域对象.getAttribute("name"),EL使JSP写起来更简单、简洁。主要用于获取作用域中的数据。
-
${scope.name}获取具体某个作用域中的数据
-
${name}获取作用域中的数据,主要查找{pageContext、request、session、application}
使用EL获取作用域中的对象调用属性时,只能访问对象的get方法,必须遵守命名规范定义
EL表达式和jsp脚本区别:
-
<%=request.getAttribute() %>没有找到返回null
-
${requestScope.name}没找到返回""
EL表达式语言定义了11个隐式对象
隐含对象 | 描述 |
---|---|
pageScope | page作用域 |
requestScope | request作用域 |
sessionScope | session作用域 |
applicationScope | application作用域 |
param | Request对象的参数,字符串 |
paramValues | Request对象的参数,字符串集合 |
header | HTTP信息头,字符串 |
headerValues | HTTP信息头,字符串集合 |
initParam | 上下文初始化参数 |
cookie | Cookie值 |
pageContext | 当前页面的pageContext |
其他:
empty关键字:${empty 变量},判断是否为空,返回true/false
EL的不足
-
EL主要是用于作用域获取数据,虽然可以做运算判断,但是得到的都是一个结果,做展示
-
EL不存在流程控制。比如判断。
-
EL对于集合只能做单点访问,不能实现遍历操作。比如循环。
JSTL标准标签库
简介:
(1)JSTL:全称为Java Server Standard Tag Library
(2)JSP标准标签库(JSTL)是一个JSP标签集合
可对EL获取的数据进行逻辑操作,与EL合作完成数据的展示
格式:
-
导入两个jar文件:standard.jar和jstl.jar文件拷贝到/WEB-INF /lib/下
-
在JSP页面引入标签库<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" >
prefix起到提示作用,表明是JSTL标签,一般写c。
条件判断
<c:if>
单条件判断标签,语法:<c:if test="条件"></c:if>
<c:choose>
多条件判断标签
<c:choose>
<c:when test="条件1">结果1</c:when>
<c:when test="条件2">结果2</c:when>
......
<c:when test="条件n">结果n</c:when>
<c:otherwise>结果m</c:otherwise>
</c:choose>
迭代标签
<c:foreach>
<c:foreach var="变量名" items="集合" begin="起始下标" end="结束下标" step="间隔长度" varstatus="遍历状态">
</c:foreach>
var、items必须要写
url标签
(1)在Cookie禁用的情况下,通过重写URL拼接JESSIONID来传递ID值。便于下一次访问时仍可查到上一次的Session对象
(2)语法:<c:url context='${pageContext.request.contextPath}' value='/xxxController' />
(3)注意:所有涉及到页面跳转或者重定向跳转时。都应该使用URL重写
MVC框架
简介:
MVC又称为编程模式,是一种软件设计思想,将数据操作、页面显示、业务逻辑分为三个层级(模块),独立完成,相互调用,MVC并不是Java独有的,现在几乎所有的B/S的结构都采用了MVC模式:
-
视图View:视图是用户看到并与之交互的界面,比如HTML(静态资源),JSP(动态资源)等等
-
控制器Controller:控制器即使控制请求的处理逻辑,对请求进行处理,负责流程跳转(转发和重定向)
-
模型Model:对客观世界的一种代表和模拟(业务模拟、对象模拟)
优点:
-
低耦合性:模块与模块之间的关联性不强,不与某一种具体实现产生密不可分的关联性
-
高维护性:基于低耦合性,可做到不同层级的功能模块灵活更换、插拔
-
高重用性:相同的数据库操作,可以服务于不同的业务处理。将数据作为独立模块,提高重用性。
三层架构和MVC区别:
-
MVC强调的是视图和业务代码的分离。严格的说MVC其实关注的是Web层。View就是单独的页面,如JSP、HTML等,不负责业务处理,只负责数据的展示。而数据封装到Model里,有Controller负责在V和M之间传递。MVC强调业务和视图分离。
-
三层架构是“数据访问层”、“业务逻辑层”、“表示层”,指的是代码之间的解耦、方便维护和复用。
数据分页显示
分页是Web应用程序非常重要的一个技术。数据库中的数据可能是成千上万的,不可能把这么多的数据一次显示在浏览器上面。一般根据每行数据在页面上所占的空间设置每页显示若干行。
步骤:
第一步:确定每页显示的数据数量
第二步:确定分页显示所需的总页数
第三步:编写SQL查询语句,实现数据查询
第四步:在JSP页面中进行分页显示设置
创建Page类
@Data
public class Page {
private Integer pageIndex;//页码
private Integer pageSize;//页大小 显示多少行数据
private Integer totalCounts;//数据的总行数
private Integer totalPages;//总页数
private Integer startRows;//起始行
public Page(Integer pageIndex) {
this(pageIndex, 8);
}
public Page(Integer pageIndex, Integer pageSize) {
this.pageIndex = pageIndex;
this.pageSize = pageSize;
this.setStartRows((pageIndex - 1) * pageSize);
}
public void setTotalCounts(Integer totalCounts) {
this.totalCounts = totalCounts;
this.setTotalPages(totalCounts % pageSize == 0 ? totalCounts / pageSize : totalCounts / pageSize + 1);
}
}
serviceImpl实现类
public class EmpDaoImpl01 implements EmpDao01 {
private QueryRunner queryRunner = new QueryRunner();
@Override
public List<Emp> selectAll(Page page) {
try {
List<Emp> emps = queryRunner.query(DbUtils.getConnection(),"select * from emp limit ?,?",new BeanListHandler<Emp>(Emp.class),page.getStartRows(),page.getPageSize());
return emps;
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
@Override
public long selectCount() {
try {
return queryRunner.query(DbUtils.getConnection(),"select count(*) from emp;",new ScalarHandler<>());
} catch (SQLException e) {
e.printStackTrace();
}
return 0;
}
}
controller:
@WebServlet(name = "SelectAllEmpServlet", value = "/SelectAllEmpServlet")
public class SelectAllEmpServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String pageIndex = request.getParameter("pageIndex");
if(pageIndex==null){//如果是第一次访问
pageIndex ="1";
request.setAttribute("pageIndex",pageIndex);
}
Page page = new Page(Integer.valueOf(pageIndex));
System.out.println(page);
//调用Dao,获取所有数据
EmpDao01 empDao01 = new EmpDaoImpl01();
long count = empDao01.selectCount();
page.setTotalCounts((int)count);
List<Emp> emps = empDao01.selectAll(page);
request.setAttribute("emps",emps);
request.setAttribute("page",page);
//转发
request.getRequestDispatcher("/showAllEmp.jsp").forward(request,response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
前端显示jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>emp表的所有数据</h1>
<table border="1" cellspacing="0" width="800px">
<tr>
<th>员工编号</th>
<th>员工姓名</th>
<th>员工年龄</th>
<th>员工工资</th>
</tr>
<c:forEach var="emp" items="${emps}">
<tr>
<td>${emp.eid}</td>
<td>${emp.ename}</td>
<td>${emp.age}</td>
<td>${emp.salary}</td>
</tr>
</c:forEach>
<tr>
<td colspan="4">
<a href="<c:url context='${pageContext.request.contextPath}' value='/SelectAllEmpServlet?pageIndex=1' />">首页</a>
<c:if test="${page.pageIndex > 1}">
<a href="<c:url context='${pageContext.request.contextPath}' value='/SelectAllEmpServlet?pageIndex=${page.pageIndex - 1}' />">上一页</a>
</c:if>
<c:if test="${page.pageIndex == 1}">
<a>上一页</a>
</c:if>
<c:if test="${page.pageIndex < page.totalPages}">
<a href="<c:url context='${pageContext.request.contextPath}' value='/SelectAllEmpServlet?pageIndex=${page.pageIndex + 1}'/>">下一页</a>
</c:if>
<c:if test="${page.pageIndex == page.totalPages}">
<a>下一页</a>
</c:if>
<a href="<c:url context='${pageContext.request.contextPath}' value='/SelectAllEmpServlet?pageIndex=${page.totalPages}'/>">尾页</a>
</td>
</tr>
</table>
</body>
</html>
文件上传与下载
在项目中,文件的上传和下载是常见的功能。当用户在前端页面点击文件上传后,用户上传的文件数据提交给服务器端,实现保存。当用户在前端页面点击文件上传后,用户上传的文件数据提交给服务器端,实现保存。 <form action="......" method="post">......</form>
前端要点:
1.提交方式method属性必须是post
2.表单的enctype属性值必须为multipart/form-data
3.想要实现多选(ctrl+单击),添加:multiple="multiple"
UUID解决文件重名:当上传重名的文件时,会发生覆盖现象。为了防止文件覆盖的现象发生,我们需要给上传的文件生成一个唯一的文件名。生成唯一文件名可以使用UUID类拼接文件名来实现。
public class UUIDDemo01 {
/*
UUID类表示通用唯一标识符(UUID)的类。UUID表示一个128位的值。
public static UUID randomUUID()获取类型 4(伪随机生成的)UUID 的静态工厂。 使用加密的强伪随机数生成器生成该 UUID。
*/
//返回一个字符串类型的UUID值
public static String strUuid01(){
return UUID.randomUUID().toString();
}
public static String strUuid02(){
return UUID.randomUUID().toString().replaceAll("-","");
}
public static String strUuid03(String fileName){
return UUID.randomUUID().toString().replaceAll("-","")+"_"+fileName;
}
public static void main(String[] args) {
System.out.println(strUuid01());
System.out.println(strUuid02());
System.out.println(strUuid03("xx.jpg"));
}
}
细节:限制上传文件的类型,在收到文件上传名时,判断后缀名是否合法;每次上传的文件都会存储在/WEB-INF/upload目录中,为了防止一个目录下面出现大量的上传文件,要使用hash算法生成二级、三级,甚至更多级的目录,散列存储上传的文件。
controller:
@WebServlet(name = "UploadServlet05", value = "/UploadServlet05")
//maxFileSize:单个文件最大大小 maxRequestSize:一次请求多个文件一共的最大大小
@MultipartConfig(maxFileSize = 1024 * 1024 * 100, maxRequestSize = 1024 * 1024 * 200)
public class UploadServlet05 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//实现文件上传
//1、设置乱码
//设置请求参数的编码格式,这种方式对get请求方式无效
request.setCharacterEncoding("UTF-8");
//设置响应编码格式为UTF-8
response.setContentType("text/html;charset=UTF-8");
//2、获取数据
String username = request.getParameter("username");
Part file1 = request.getPart("file1");
//获取上传文件保存路径(真实路径)
String uploadPath = request.getServletContext().getRealPath("/WEB-INF/upload");
System.out.println("文件上传路径:" + uploadPath);
//创建文件夹对象
File file = new File(uploadPath);
//判断文件夹是否存在,如果不存在,就创建文件夹
if (!file.exists()) {
file.mkdirs();
}
//判断上传的文件是否为空,如果不是空,进行保存
if (file1 != null) {
//获取上传文件名称
String oldName = file1.getSubmittedFileName();
//文件类型限制
//创建一个集合存放允许上传的文件的类型(后缀名)
//判断所上传的文件在当前集合当中是否包含
List<String> nameList = new ArrayList<String>();
nameList.add(".jpg");
nameList.add(".bmp");
nameList.add(".png");
//截取文件名名,获取文件的后缀名
String extName = oldName.substring(oldName.lastIndexOf("."));
if(!nameList.contains(extName)){
response.getWriter().println(file1.getSubmittedFileName() + "不符合文件上传规则");
return;
}
//给获取的文件名绑定一个唯一的UUID值
String newName = UploadUtils.newFileName(oldName);
//生成二级、三级目录,实现散列存储
String newPath = UploadUtils.newFilePath(uploadPath,oldName);
file1.write(newPath + File.separator + newName);
}
response.getWriter().println(file1.getSubmittedFileName() + "上传成功");
}
}