文章目录
- 05【JSP-MVC】
- 一、JSP简介
- 1.1 JSP概述
- 1.1.1 HTML和Servlet的弊端
- 1.1.1 什么是JSP
- 1.2 JSP体验:
- 1.2.2 JSP的执行过程
- 1.2.2 JSP和Servlet是什么关系?
- 二、JSP的脚本元素
- 2.1 JSP中的注释:
- 2.2 JSP脚本表达式
- 2.3 JSP代码片段
- 2.4 JSP声明
- 2.5 JSP页面的三种脚本小结:
- 2.6 pageContext域
- 2.6.1 页面域
- 2.6.2 页面域测试:
- 2.7 JSP九大内置对象
- 2.7.1 Request对象
- 2.7.2 Response对象
- 2.7.3 Out对象
- 2.7.4 Session对象
- 2.7.5 Application对象
- 2.7.6 PageContext对象
- 2.7.7 Config对象
- 2.7.8 Page
- 2.7.9 Exception对象
- 三、EL表达式
- 3.1 EL表达式的作用
- 3.1.1 什么是EL
- 3.1.2 EL表达式的作用:
- 3.2 获取数据
- 3.2.1 指定域获取数据
- 3.2.2 示例:取出不同作用域中的值
- 3.2.3 小结:从四个作用域中取值
- 3.3 EL表达式获取不同类型的数据
- 3.4 练习题:
- 四、EL中使用表达式
- 4.1 算术表达式 :
- 4.2 比较表达式
- 4.3 逻辑表达式 :
- 4.4 三元运算:
- 4.5 判空表达式:
- 4.6 使用上面所有的运算符
- 五、核心标签库
- 5.1 JSTL标签库
- 5.1.1 JSTL使用步骤
- 5.2 判断标签\<c:if\>
- 5.3 多分支标签choose
- 5.4 遍历标签`<c:forEach>`
- 5.4.1 参数
- 5.4.2 varStatus属性:
- 5.4.3 遍历集合:
- 5.4.4 遍历数组和Map:
- 六、三层架构与MVC
- 6.1 JavaWEB发展史
- 6.1.1 Model1
- 6.1.2 Model2 第一代
- 6.1.2 Model2 第二代
- 6.2 什么是MVC
- 6.1.1 JavaWeb对MVC的实现
- 6.3 三层架构开发模式
- 6.4 MVC中的三层
- 七、综合案例:完成用户显示列表案例
- 7.1 案例需求
- 7.2 案例效果
- 7.3 实现步骤
- 7.3.1 执行SQL语句
- 7.3.2 导入jar包、配置文件、实体类和工具类
- 7.3.3 数据源工具类
- 7.3.4 验证码类
- 7.3.5 用户登录
- 7.3.5.1 登录页面
- 7.3.5.2 LoginServlet:
- 7.3.5.3 UserService:
- 7.3.5.4 UserDao
- 7.3.6 用户列表
- 7.3.6.1 列表页面
- 7.3.6.2 ListServlet:
- 7.3.6.3 UserService:
- 7.3.6.4 UserDao
05【JSP-MVC】
一、JSP简介
1.1 JSP概述
1.1.1 HTML和Servlet的弊端
我们之前学习过HTML和Servlet,HTML属于静态资源,专门用于布局页面,方便页面美化操作,写JS脚本和CSS代码都比较方便,但是由于HTML是静态资源,不能制作动态的内容。
后来我们学习了Servlet,Servlet属于动态资源,可以编写Java脚本,让网友具备更多的动态交互感;但Servlet的缺点也非常明显,那就是不方便编写HTML/CSS/JS等前端代码;
- 我们来观察一下Servlet编写的一个布局:
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.List;
/**
* @author lscl
* @version 1.0
* @intro:
*/
@WebServlet("/demo01")
public class Demo01Servlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 模拟从数据库里面查询
List<String> mountains_01 = Arrays.asList("庐山", "黄山", "雁荡山");
List<String> mountains_02 = Arrays.asList("东岳泰山", "西岳华山", "南岳衡山", "北岳恒山", "中岳嵩山");
response.setContentType("text/html;charset=utf8");
PrintWriter out = response.getWriter();
out.println(" <head>\n" +
" <title>demo</title>\n" +
" <style>\n" +
" .s1{\n" +
" color:blue;\n" +
" }\n" +
" .s2{\n" +
" color:gold;\n" +
" }\n" +
" </style>\n" +
" </head>");
out.println("<h2>三山<h2>");
out.println("<ul class='s1'>");
for (String mountain : mountains_01) {
out.println("<li>" + mountain + "</li>");
}
out.println("</ul>");
out.println("<hr>");
out.println("<h2>五岳<h2>");
out.println("<ul class='s2'>");
for (String mountain : mountains_02) {
out.println("<li>" + mountain + "</li>");
}
out.println("</ul>");
}
}
访问:http://localhost:8080/demo01
总结:
- HTML:
- 优点:方便页面美化操作,写JS脚本和CSS代码都比较方便;
- 缺点:不能制作动态的内容;
- Servlet:
- 优点:可以制作动态内容;
- 缺点:不方便写CSS和JS代码;
1.1.1 什么是JSP
JSP(全称JavaServer Pages)是由[Sun Microsystems](https://baike.baidu.com/item/Sun Microsystems)公司主导创建的一种动态网页技术标准。JSP部署于网络服务器上,可以响应客户端发送的请求,并根据请求内容动态地生成HTML、XML或其他格式文档的Web网页,然后返回给请求者。JSP技术以Java语言作为脚本语言,为用户的HTTP请求提供服务,并能与服务器上的其它Java程序共同处理复杂的业务需求。
JSP将Java代码和特定变动内容嵌入到静态的页面中,实现以静态页面为模板,动态生成其中的部分内容。JSP引入了被称为“JSP动作”的XML标签,用来调用内建功能。另外,可以创建JSP标签库,然后像使用标准HTML或XML标签一样使用它们。标签库能增强功能和服务器性能,而且不受跨平台问题的限制。JSP文件在运行时会被其编译器转换成更原始的Servlet代码。JSP编译器可以把JSP文件编译成用Java代码写的Servlet,然后再由Java编译器来编译成能快速执行的二进制机器码,也可以直接编译成二进制码。
Tips:JSP本质上就是一个Servlet,属于动态技术;
- 快速体验JSP:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>测试页面</title>
<style>
h1 {
color: red;
}
</style>
</head>
<body>
<h1>我是HTML代码</h1>
<%
System.out.println("我是Java代码");
%>
</body>
</html>
观察idea控制台的输出语句;
1.2 JSP体验:
JSP既有HTML的优点,方便制作和美化。又可以在页面写Java代码,可以制作动态内容。
- 快速体验JSP:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>测试页面</title>
<style>
h1 {
color: red;
}
</style>
</head>
<body>
<h1>我是HTML代码</h1>
<%
System.out.println("我是Java代码");
%>
</body>
</html>
1.2.2 JSP的执行过程
JSP首先会将代码翻译成Servlet的Java代码,然后再编译成字节码文件执行。
- Servlet生成的位置:
C:\Users\Administrator\AppData\Local\JetBrains\IntelliJIdea2020.1\tomcat\Tomcat_8_0_43_06_JSP_EL_JSTL_MVC\work\Catalina\localhost\01_jsp\org\apache\jsp
1.2.2 JSP和Servlet是什么关系?
查看源码:
public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase
public abstract class HttpJspBase extends HttpServlet
我们写的JSP在最后都会被翻译成Servlet,也就是说JSP实质上就是一个Servlet;
- 那么JSP什么时候翻译成Servlet?生成多少次?
浏览器第一次访问JSP的时候,由Tomcat将JSP翻译成了Servlet,并且编译成字节码文件,生成1次。
我们的代码运行在_jspService()方法中
-
HTML代码: 通过out通过直接write()输出
-
Java代码:原样放在翻译以后的Servlet中
/*
* Generated by the Jasper component of Apache Tomcat
* Version: Apache Tomcat/8.0.43
* Generated at: 2022-05-05 01:09:56 UTC
* Note: The last modified time of this file was set to
* the last modified time of the source file after
* generation to assist with modification tracking.
*/
package org.apache.jsp;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletResponse;
public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent,
org.apache.jasper.runtime.JspSourceImports {
private static final javax.servlet.jsp.JspFactory _jspxFactory =
javax.servlet.jsp.JspFactory.getDefaultFactory();
private static java.util.Map<java.lang.String, java.lang.Long> _jspx_dependants;
private static final java.util.Set<java.lang.String> _jspx_imports_packages;
private static final java.util.Set<java.lang.String> _jspx_imports_classes;
static {
_jspx_imports_packages = new java.util.HashSet<>();
_jspx_imports_packages.add("javax.servlet");
_jspx_imports_packages.add("javax.servlet.http");
_jspx_imports_packages.add("javax.servlet.jsp");
_jspx_imports_classes = null;
}
private volatile javax.el.ExpressionFactory _el_expressionfactory;
private volatile org.apache.tomcat.InstanceManager _jsp_instancemanager;
public java.util.Map<java.lang.String, java.lang.Long> getDependants() {
return _jspx_dependants;
}
public java.util.Set<java.lang.String> getPackageImports() {
return _jspx_imports_packages;
}
public java.util.Set<java.lang.String> getClassImports() {
return _jspx_imports_classes;
}
public javax.el.ExpressionFactory _jsp_getExpressionFactory() {
if (_el_expressionfactory == null) {
synchronized (this) {
if (_el_expressionfactory == null) {
_el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
}
}
}
return _el_expressionfactory;
}
public org.apache.tomcat.InstanceManager _jsp_getInstanceManager() {
if (_jsp_instancemanager == null) {
synchronized (this) {
if (_jsp_instancemanager == null) {
_jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());
}
}
}
return _jsp_instancemanager;
}
public void _jspInit() {
}
public void _jspDestroy() {
}
public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
throws java.io.IOException, javax.servlet.ServletException {
final java.lang.String _jspx_method = request.getMethod();
if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method) && !javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {
response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSPs only permit GET POST or HEAD");
return;
}
final javax.servlet.jsp.PageContext pageContext;
javax.servlet.http.HttpSession session = null;
final javax.servlet.ServletContext application;
final javax.servlet.ServletConfig config;
javax.servlet.jsp.JspWriter out = null;
final java.lang.Object page = this;
javax.servlet.jsp.JspWriter _jspx_out = null;
javax.servlet.jsp.PageContext _jspx_page_context = null;
try {
response.setContentType("text/html;charset=UTF-8");
pageContext = _jspxFactory.getPageContext(this, request, response,
null, true, 8192, true);
_jspx_page_context = pageContext;
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
_jspx_out = out;
out.write("\r\n");
out.write("<html>\r\n");
out.write("<head>\r\n");
out.write(" <title>测试页面</title>\r\n");
out.write(" <style>\r\n");
out.write(" h1 {\r\n");
out.write(" color: red;\r\n");
out.write(" }\r\n");
out.write(" </style>\r\n");
out.write("</head>\r\n");
out.write("<body>\r\n");
out.write("<h1>我是HTML代码</h1>\r\n");
System.out.println("我是Java代码");
out.write("\r\n");
out.write("\r\n");
out.write("</body>\r\n");
out.write("</html>\r\n");
} catch (java.lang.Throwable t) {
if (!(t instanceof javax.servlet.jsp.SkipPageException)) {
out = _jspx_out;
if (out != null && out.getBufferSize() != 0)
try {
if (response.isCommitted()) {
out.flush();
} else {
out.clearBuffer();
}
} catch (java.io.IOException e) {
}
if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
else throw new ServletException(t);
}
} finally {
_jspxFactory.releasePageContext(_jspx_page_context);
}
}
}
二、JSP的脚本元素
2.1 JSP中的注释:
JSP中的三种注释 | 说明 |
---|---|
HTML | <!-- 注释 --> 只能注释静态内容,不能注释Java代码。 通过浏览查看源代码可以看到的 |
Java | 与以前是一样的,在网页中看不到,但在翻译以后Servlet中有。 // 单行注释 /* 多行注释 */ /** 文档注释 */ |
JSP | <%-- 动态内容 --%> 可以注释JSP上任何元素 网页中没有,在生成的Java源代码中也没有 |
- 面试题:如果使用HTML注释JSP脚本元素会怎么样?
如:
<!-- <%out.print(3*5);%> -->
在网页上看不到内容,但JSP的脚本还是会正常的执行,查看HTML源代码能看到被注释的内容;
2.2 JSP脚本表达式
JSP脚本表达式 | 说明 |
---|---|
语法 | <%= 变量名或表达式 %> 翻译成Servlet变成out.print()打印输出 |
作用 | 直接输出变量的值或对表达式进行计算 |
- JSP代码演示
JSP表达式:
<%
String name = "张三";
%>
<%=name%> <br>
<%=3*4%><br>
查看翻译后的代码:
tips:
<%=xxx%>
采用的是out的print方法输出;
2.3 JSP代码片段
JSP代码片段 | 说明 |
---|---|
语法 | <% 一行或多行Java代码; %> 例:<% String name=‘abc’ %> |
作用 | 在JSP的页面上执行一段Java代码,必须符合Java的语法规则。每行代码以分号结束。 |
-
演示:在脚本中创建一个ArrayList,添加四个名字,在ol-li中有序列表输出,使用Java中的for循环输出。
-
执行效果:
- 代码:
<body>
<%
//将一个数组转成List对象
List<String> names = Arrays.asList("江西", "陕西", "广西", "山西");
%>
<ol>
<% //for循环输出
for (String n : names) {
%>
<li>
<%=n%>
</li>
<%}%>
</ol>
</body>
- 生成的Servlet代码:
// 将一个数组转成List对象
List<String> names = Arrays.asList("江西", "陕西", "广西", "山西");
out.write("\n");
out.write("<ol>\n");
out.write(" ");
// for循环输出
for (String n : names) {
out.write("\n");
out.write(" <li>\n");
out.write(" ");
out.print(n);
out.write("\n");
out.write(" </li>\n");
out.write(" ");
}
2.4 JSP声明
JSP声明 | 说明 |
---|---|
语法 | <%! 全局变量或方法 %>,例:<%! String name='abc' %> |
作用 | 用于在JSP页面上声明全局变量或方法 |
- 演示:
-
在脚本中创建一个字符串,使用表达式输出
-
在声明中也创建一个同名的字符,表达式输出,会不会有问题?
- 代码:
<body>
<%--定义代码片段,代码生成在service方法中--%>
<% String name="张三";%>
<%--定义声明片段,代码生成在类中方法外(成员变量)--%>
<%! String name="李四";%>
<h1>成员变量: <%=this.name%></h1>
<h1>局部变量: <%=name%></h1>
</body>
- 生成的Servlet代码
package org.apache.jsp;
public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent,
org.apache.jasper.runtime.JspSourceImports {
// 李四在成员变量中
String name = "李四";
.....
public void _jspInit() {
}
public void _jspDestroy() {
}
public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
throws java.io.IOException, javax.servlet.ServletException {
response.setContentType("text/html;charset=UTF-8");
....
// 张三在局部变量中
String name = "张三";
out.print(name);
out.print(this.name);
....
} catch (java.lang.Throwable t) {
} finally {
}
}
}
- 结论:声明部分声明变量是在类中的成员变量,全局变量。而在JSP代码片段中声明的变量是局部变量,声明在_jspService()方法中。
2.5 JSP页面的三种脚本小结:
组成部分 | 功能 | 语法 |
---|---|---|
JSP代码片段 | 在JSP中执行Java代码 | <% Java代码; %> 如:<% String name='abc'; %> |
JSP脚本表达式 | 在JSP中输出变量值 | <%= 变量%> 如:<%=name %> |
JSP声明 | 声明成员变量或方法 | <%! 声明 %> 如:<%! String name='abc' %> |
- 案例:分别输出脚本变量和作用域中变量值
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%
int m=5;
//向使用域中添加一个变量
request.setAttribute("n", 6);
%>
输出m:
<%=m%><br>
输出作用域中值:
<%=request.getAttribute("n")%><br>
</body>
</html>
结果:
2.6 pageContext域
page: 只能在当前页面中有效
request: 一次请求
session: 一次会话
context: 整个服务器
2.6.1 页面域
pageContext域是servlet中4个域对象中最后一个了,页面域的大小是4大域对象中最小的,只在当前页面上有效,不同的JSP页面之间不能实现数据的共享(即使是一次请求)。比请求域范围还要小。
- 页面域对象名:类PageContext,在JSP中对应了一个内置对象名:
pageContext
四个与页面域有关的方法:
页面域操作有关的方法 | 说明 |
---|---|
void setAttribute(String key, Object value) | 向页面域中添加键和值 |
Object getAttribute(String key) | 从页面域中得到值 |
void removeAttribute(String key) | 删除页面域中键值对 |
Object findAttribute(String key) | 自动从四个作用域中去查某个键,从小到大的范围来查找,如果找到就停止。如果没有找到,返回null |
page域的内容只能作用在当前页面
pageContext<request<session<ServletContext
2.6.2 页面域测试:
- demo01.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%
// 分别在page域和request域中存入一个值
pageContext.setAttribute("pageContextMsg","hello page!");
request.setAttribute("requestMsg","hello request!");
// 转发到demo02.jsp(还是在一次请求中)
request.getRequestDispatcher("/demo02.jsp").forward(request,response);
%>
</body>
</html>
- demo02.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>page域: <%=request.getAttribute("pageContextMsg")%></h1>
<h1>request域: <%=request.getAttribute("requestMsg")%></h1>
</body>
</html>
访问结果:
2.7 JSP九大内置对象
2.7.1 Request对象
Request对象是javax.servlet.http.HttpServletRequest类的实例。代表请求对象,主要用于接受客户端通过HTTP协议连接传输到服务器端的数据。比如表单中的数据、网页地址后带的参数等。
2.7.2 Response对象
Response对象是javax.servlet.http.HttpServletResponse类的实例。代表响应对象,主要用于向客户端发送数据。
2.7.3 Out对象
Out对象是javax.servlet.jsp.JspWriter类的实例。主要用于向客户端浏览器输出数据。
2.7.4 Session对象
Session 对象是javax.servlet.http.HttpSession类的实例。主要用来保持在服务器与一个客户端之间需要保留的数据,比如在会话期间保持用户的登录信息等,会话状态维持是Web应用开发者必须面对的问题。当客户端关闭网站的所有网页或关闭浏览器时,session对象中保存的数据会自动清除。由于Htp协议是一个无状态协议,不保留会话间的数据,因此通过session对象扩展了htp的功能。比如用户登录一个网站之后,登录信息会暂时保存在session对象中,打开不同的页面时,登录信息是可以共享的,一旦用户关闭浏览器或退出登录,就会清除session对象中保存的登录信息。
2.7.5 Application对象
Application对象是javax.servlet.ServletContext类的实例。主要用于保存用户信息,代码片段的运行环境;它是一个共享的内置对象,即一个容器中的多个用户共享一个application对象,故其保存的信息被所有用户所共享。
2.7.6 PageContext对象
PageContext对象是javax.servlet.jsp.PageContext类的实例。用来管理网页属性,为JSP页面包装页面的上下文,管理对属于JSP中特殊可见部分中已命名对象的访问,它的创建和初始化都是由JSP容器来完成的。
2.7.7 Config对象
Config对象是javax.servlet.ServletConfig类的实例。是代码片段配置对象,表示Servlet的配置。
2.7.8 Page
Page对象是javax.servlet.jsp.HttpJspPage类的实例。相当于this,用来处理JSP网页,它指的是JSP页面对象本身,或者说代表编译后的servlet对象,只有在JSP页面范围之内才是合法的。
2.7.9 Exception对象
我们可以为某个JSP页面设置错误处理页面,当JSP页面发生异常时,请求将会被跳转到指定的错误页面:
<%@ page contentType="text/html;charset=UTF-8" language="java"
errorPage="/error.jsp" %> <%--当前页面如果发生异常就跳转到error.jsp页面--%>
<html>
<head>
<title>Title</title>
</head>
<body>
<%
// 模拟异常
int i = 1 / 0;
%>
</body>
</html>
错误处理页面:
<%@ page contentType="text/html;charset=UTF-8" language="java"
isErrorPage="true" %> <%--设置当前页面是一个错误处理页面--%>
<html>
<head>
<title>Title</title>
</head>
<body>
<%--获取上一个页面触发的异常--%>
<h1>页面出现错误啦!错误信息:<%=exception.getMessage()%></h1>
</body>
</html>
Tips:
1)只有当前的JSP页面设置了
isErrorPage=true
时才可以使用exception内置对象;2)并不是所有的JSP页面都有九大内置对象,只有错误页面才有九大内置对象,普通页面只有八大内置对象
三、EL表达式
3.1 EL表达式的作用
3.1.1 什么是EL
EL:Expression Language
表达式语言
- 语法:
${ 变量名或表达式 }
3.1.2 EL表达式的作用:
1)用于输出作用域中的变量值
2)用于进行各种运算:算术,逻辑,关系,三元运算等
3.2 获取数据
3.2.1 指定域获取数据
四个与页面域有关的方法:
页面域操作有关的方法 | 说明 |
---|---|
void setAttribute(String key, Object value) | 向页面域中添加键和值 |
Object getAttribute(String key) | 从页面域中得到值 |
void removeAttribute(String key) | 删除页面域中键值对 |
Object findAttribute(String key) | 自动从四个作用域中去查某个键,从小到大的范围来查找,如果找到就停止。如果没有找到,返回null |
page域的内容只能作用在当前页面
pageContext<request<session<ServletContext
3.2.2 示例:取出不同作用域中的值
- 效果:
- 代码:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%
//向页面域中添加一个字符串
pageContext.setAttribute("name", "页面域");
//请求域
request.setAttribute("name", "请求域");
//会话域
session.setAttribute("name", "会话域");
//上下文域
application.setAttribute("name", "上下文域");
%>
JSP写法:
<%=pageContext.getAttribute("name")%>
EL的写法:
${pageScope.name}
<hr>
JSP写法:
<%=request.getAttribute("name")%>
EL的写法:
${requestScope.name}
<hr>
JSP写法:
<%=session.getAttribute("name")%>
EL的写法:
${sessionScope.name}
<hr>
JSP写法:
<%=application.getAttribute("name")%>
EL的写法:
${applicationScope.name}
<hr>
JSP写法:
<%=pageContext.findAttribute("name")%>
EL的写法:
${name}
<hr>
</body>
</html>
EL表达式默认从最小的域中取值,如果最小的域中取值,如果没有就往上一级域取值,以此类推;
3.2.3 小结:从四个作用域中取值
作用域 | Java代码 | EL的写法 | 范围大小 |
---|---|---|---|
页面域 | <%=pageContext.getAttribute(“键名”)%> | ${pageScope.键名} | 1 |
请求域 | <%=request.getAttribute(“键名”)%> | ${requestScope.键名} | 2 |
会话域 | <%=session.getAttribute(“键名”)%> | ${sessionScope.键名} | 3 |
上下文域 | <%=application.getAttribute(“键名”)%> | ${applicationScope.键名} | 4 |
自动查找 | <%=pageContext.findAttribute(“键名”)%> | ${键名} |
- 查看每个域对象的大小:
index04.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>
<%-- 在4个域对象中存入值 --%>
<% pageContext.setAttribute("page", "hello"); %>
<% request.setAttribute("request", "hello"); %>
<% session.setAttribute("session", "hello"); %>
<% application.setAttribute("application", "hello"); %>
<%-- 查看每个域对象的范围大小 --%>
<%=pageContext.getAttributesScope("page")%>
<%=pageContext.getAttributesScope("request")%>
<%=pageContext.getAttributesScope("session")%>
<%=pageContext.getAttributesScope("application")%>
</h1>
</body>
</html>
效果如下:
3.3 EL表达式获取不同类型的数据
示例:用EL取出不同的数据类型
- 执行效果:
- 注意,键名中如果有特殊字符的写法
变量名[“键名”] |
---|
可以使用双引号或单引号,如:${map[“no3-no4”]} |
- index05代码:
<%@ page import="com.dfbz.entity.User" %>
<%@ page import="java.util.Arrays" %>
<%@ page import="java.util.List" %>
<%@ page import="java.util.HashMap" %>
<%@ page import="com.dfbz.entity.User" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>得到不同类型的值</title>
</head>
<body>
<%
//将员工对象放在页面域
User user = new User(1, "张三");
//放到页面域中
pageContext.setAttribute("user", user);
%>
<h2>得到JavaBean的属性值</h2>
<%--本质上是调用get方法--%>
ID:${user.id}, 用户名:${user.username}
<hr>
<%
List<String> names = Arrays.asList("浙江金华", "福建圃田", "湖南怀化");
//放在请求域中
request.setAttribute("names", names);
%>
<h2>取出集合List中元素</h2>
${names[0]} ${names[1]} ${names[2]}
<%
int[] nums = {100, 200, 300, 400};
//数组放在页面域
pageContext.setAttribute("nums", nums);
%>
<h2>取出数组中元素</h2>
${nums[0]} ${nums[1]} ${nums[2]} ${nums[3]}
<%
HashMap<String, String> maps = new HashMap<>();
maps.put("no1", "辽宁辽阳");
maps.put("no2", "山东威海");
maps.put("no3-no4", "河北承德");
//放在请求域
request.setAttribute("maps", maps);
%>
<h2>取出Map中元素</h2>
<%--map对象.键名--%>
${maps.no1} ${maps["no2"]} ${maps["no3-no4"]}
</body>
</html>
3.4 练习题:
- 如果一个会话域中保存了一个user对象,请问以下哪几种取值可以取出user对象的username属性值。
A: ${user.username}
B: ${sessionScope.user.username}
C: ${username}
D: <%=((User)pageContext.findAttribute(“user”)).getUsername() %>
E: <%=((User)session.getAttribute(“user”)).getUsername() %>
点我看答案
四、EL中使用表达式
4.1 算术表达式 :
算术运算符 | 说明 | 范例 | 结果 |
---|---|---|---|
+ | 加 | ${1+1} | 2 |
- | 减 | ${2-1} | 1 |
* | 乘 | ${1*1} | 1 |
/或div | 除 | ${5 div 2} 或${5 / 2} | 2.5 |
%或mod | 取余 | ${5 mod 2}或 ${5%2} | 1 |
4.2 比较表达式
关系运算符 | 说明 | 范例 | 结果 |
---|---|---|---|
==或 eq | 等于(equal) | ${1 eq 1} 或 ${1==1} | true |
!= 或 ne | 不等于(not equal) | ${1 not equal 1} ${1 != 1} | false |
< 或 lt | 小于(Less than) | ${1 lt 2} ${1<2} | true |
<=或 le | 小于等于(Less than or equal) | ${1 <= 1} | true |
> 或 gt | 大于(Greater than) | ${1 > 2} | false |
>=或 ge | 大于等于(Greater than or equal) | ${1 >=1} | true |
4.3 逻辑表达式 :
逻辑运算符 | 说明 | 范例 | 结果 |
---|---|---|---|
&& 或 and | 交集(与) | ${true and false}或${true && false} | false |
|| 或 or | 并集(或) | ${true or false } 或 `${true | |
! 或 not | 非 | ${not true} 或 ${! true} | false |
4.4 三元运算:
语法:${逻辑判断?真的值:假的值}
示例:${1>1?"hello":"no hello"}
4.5 判空表达式:
${empty 变量名} |
---|
如果变量名在作用域中为空,不存在,返回true |
如果变量名为空串,返回true |
变量名是一个集合,如果集合中没有元素,返回true |
4.6 使用上面所有的运算符
<%@ page import="java.util.ArrayList" %>
<%@ page import="java.util.List" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h2>算术运算符</h2>
${1+1}<br>
${2-1}<br>
${1*1}<br>
${5 div 2}<br>
${5 /2 }<br>
${5 mod 2}<br>
${5%2}<br>
<h2>比较运算符</h2>
${1 eq 1}<br>
${1 != 1}<br>
${1 lt 2}<br>
${1 <= 1}<br>
${1 > 2}<br>
${1 >=1}<br>
<h2>关系运算符</h2>
${true and false}<br>
${true || false }<br>
${not true}<br>
<h2>三元运算</h2>
${5>6?"男":"女"}
<h2>判空表达式</h2>
${empty aaa} <br>
<%
pageContext.setAttribute("bbb", "");
//集合中没有元素
List<String> names = new ArrayList<>();
// names.add("吉林通化");
pageContext.setAttribute("ccc", names);
%>
${empty bbb}<br>
${empty ccc}<br>
</body>
</html>
五、核心标签库
5.1 JSTL标签库
jstl:Java Standard Tag Library,Java标准标签库
格式:<前缀:标签名>
JSTL | 前缀 | URI固定写法,标识的作用 | 作用 |
---|---|---|---|
核心标签库 | c | http://java.sun.com/jsp/jstl/core | 用于页面上的逻辑控制,如:if、forEach |
5.1.1 JSTL使用步骤
导包jar,每个标签底层其实都是用Java代码实现的。复制daoweb/WEB-INF/lib
创建JSP页面,使用taglib的指令
<%--prefix表示前缀,固定为c,uri 标识 --%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
在JSP页面中使用这些标签,如:<c:if>
- 使用标签的格式:<前缀:标签名>,如果有主体标签,一定要加上结束标签
5.2 判断标签<c:if>
作用: 用于页面上判断
属性名 | 是否支持EL | 属性类型 | 属 性 描 述 |
---|---|---|---|
test | 支持,必须是EL | boolean | 如果EL中条件如果为真执行标签体内容,注:没有else |
示例:如果用户提交的age值大于18,则显示你已经成年,否则显示未成年。
- 执行效果
- 代码:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--prefix表示前缀,固定为c,uri 标识 --%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>标签</title>
</head>
<body>
<%--param.age是EL中内置对象,用于获取本次提交的参数--%>
<c:if test="${param.age >=18}">
你已经成年
</c:if>
<c:if test="${param.age < 18}">
小盆友,你还未成年哦!
</c:if>
</body>
</html>
5.3 多分支标签choose
作用:用于多分支判断
标签名 | 作用 |
---|---|
choose | 类似于java中swtich, choose只是一个容器,包含下面两个元素 |
when | 可以出现多个,用于每个判断条件,类似于switch中case |
otherwise | 如果上面所有的条件都不满足,执行这个内容。类似于switch中default |
案例:通过输入分数,得到评级
在一个表单grade.jsp输入一个分数,提交给自己。然后在同一个页面中根据分数输出相应的等级,80~100优秀,60~80及格 0~60不及格 其它输出分数不正确。
- 代码:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="index02.jsp">
请输入分数:
<input type="text" name="score" value="${param.score}">
<input type="submit" value="评级">
</form>
<c:if test="${not empty param.score}">
<c:choose>
<c:when test="${param.score >=80 && param.score<=100}">
<h2 style="color: red">优秀</h2>
</c:when>
<c:when test="${param.score >=60 && param.score<80}">
<h2 style="color: green">良好</h2>
</c:when>
<c:when test="${param.score >=0 && param.score<60}">
<h2 style="color: dodgerblue">不及格</h2>
</c:when>
<c:otherwise>
<h2 style="color: orange">分数不正确</h2>
</c:otherwise>
</c:choose>
</c:if>
</body>
</html>
5.4 遍历标签<c:forEach>
作用: 用于遍历集合或数组
5.4.1 参数
属性名 | 是否支持EL | 属性类型 | 属性描述 |
---|---|---|---|
items | true | 数组或集合 | 使用EL表达式,代表集合或数组 |
var | false | String | var的变量名代表集合中的每一个元素 |
varStatus | false | String | 代表每个元素的状态对象,一共有4个属性,属性的含义见下表 |
begin | true | int | 遍历从哪个元素开始,默认从第一个元素开始 |
end | true | int | 遍历到哪个元素结束,默认遍历到最后一个元素 |
step | true | int | 代表步长,遍历时每次跳几个元素,默认每次跳过一个元素 |
5.4.2 varStatus属性:
属性 | 数据类型 | 含义 |
---|---|---|
index | int | 当前元素的索引号,从0开始 |
count | int | 遍历到当前位置,一共遍历了多少个元素(默认从1开始) |
first | boolean | 如果当前遍历的是第1个元素,则返回true |
last | boolean | 如果当前遍历的是最后1个元素,则返回true |
5.4.3 遍历集合:
- 示例:学生信息:包含编号,姓名,性别,成绩。
学生实体类:
public class Student {
private Integer id;
private String name;
private Character gender;
private Integer score;
}
- 代码:
<%@ page import="java.util.Arrays" %>
<%@ page import="com.dfbz.entity.Student" %>
<%@ page import="java.util.List" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Title</title>
<style>
table {
width: 500px;
border-collapse: collapse;
}
tr {
height: 35px;
}
td {
text-align: center;
}
</style>
</head>
<body>
<%
List<Student> stuList = Arrays.asList(
new Student(1, "张三", '1', 90),
new Student(2, "李四", '1', 98),
new Student(3, "王五", '0', 95)
);
request.setAttribute("stuList", stuList);
%>
<table border="1">
<caption>学生信息表</caption>
<tr>
<th>状态</th>
<th>学号</th>
<th>姓名</th>
<th>性别</th>
<th>成绩</th>
</tr>
<%--
items: 表示要遍历的集合,要使用EL
var: 变量名,表示集合中的每个元素对象
begin: 从哪个元素开始遍历,默认是0
end: 到哪个元素结束
varStatus: 表示一个对象名字,当前的行对象。
有四个属性:
first: 第1个元素返回true
last: 最后1个元素返回true
count: 遍历到当前元素时,一共遍历了几个元素,从1开始
index: 当前元素的索引号,从0开始
--%>
<c:forEach items="${stuList}" var="stu" varStatus="row">
<tr ${row.index % 2 ==0 ? "style='background-color:#ccc'":"style='background-color: yellow'"}>
<td>${row.index}</td>
<td>${stu.id}</td>
<td>${stu.name}</td>
<td>${stu.gender=='1'?"男":"女"}</td>
<td>${stu.score}</td>
</tr>
</c:forEach>
</table>
</body>
</html>
5.4.4 遍历数组和Map:
<%@ page import="java.util.HashMap" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%
int[] nums = {100,200,300,400};
//数组放在页面域
pageContext.setAttribute("nums", nums);
//Map集合
HashMap<String, String> maps = new HashMap<>();
maps.put("no1", "甘肃陇南");
maps.put("no2", "陕西商洛");
maps.put("no3-no4", "黑龙江绥化");
//放在请求域
request.setAttribute("maps",maps);
%>
<h2>遍历数组</h2>
<c:forEach items="${nums}" var="n">
${n}
</c:forEach>
<h2>遍历Map</h2>
<c:forEach items="${maps}" var="entry">
${entry.key} ==> ${entry.value} <br>
</c:forEach>
</body>
</html>
六、三层架构与MVC
6.1 JavaWEB发展史
6.1.1 Model1
在Model1时代,所有的业务逻辑交给jsp单独处理完成,一个web项目只存在DB层和JSP层,所有的东西都耦合在一起,对后期的维护和扩展极为不利。
6.1.2 Model2 第一代
JSP Model2有所改进,把业务逻辑的内容放到了JavaBean中,而JSP页面负责显示以及请求调度的工作。虽然第二代比第一代好了些,但JSP还是把view和controller的业务耦合在一起。依然很不理想。
6.1.2 Model2 第二代
Model2第二代就是现在大力推广的和使用的MVC,将一个项目划分为三个模块,各司其事互不干扰,既解决了jsp所形成的耦合性,又增加了逻辑性、业务性以及复用性和维护性
6.2 什么是MVC
MVC模式(Model-View-Controller)是软件工程中的一种软件架构模式,把软件架构分为三个基本部分:模型(Model)、视图(View)和控制器(Controller)。
6.1.1 JavaWeb对MVC的实现
MVC把软件架构分为了三个部分:
- Controller:也叫控制器;功能如下:
- 1)接受前端的请求参数
- 2)调用Model获取模型数据(一般来说就是我们Java中的对象)
- 3)选择跳转的视图
- Model:也叫模型;功能如下:
- 1)接受控制器的参数
- 2)访问数据库查询数据,封装成JavaBean(如何封装JavaBean就包含了我们之前说的业务处理、逻辑运算、统计等)
- 3)返回JavaBean给控制器
- View:也叫视图,主要就是响应给客户端,一般指的是JSP,视图通过jstl等技术取出数据遍历,进行页面的渲染;
6.3 三层架构开发模式
三层架构开发模式是软件开发的一种架构模式,他将我们的软件开发代码划分为了三个代码层次,每个代码层次各司其职,降低了代码之间的耦合度;使得我们的代码更加清晰,简洁;
三层架构分为控制层(controller层)、业务层(service层)、持久层(数据层,Dao层);
- 控制层:又称表现层、web层等;控制层是请求来到后端的第一步操作,控制层主要完成以下三个操作
- 1)接受前端前端传递的参数
- 2)调用业务层进行业务逻辑处理
- 3)根据业务层响应的结果最终决定页面的转发
- 业务层:又称service层;业务层主要完成以下三个操作:
- 1)接受控制层传递的参数,调用持久层查询数据库
- 2)从持久层查询到数据之后开始进行业务的处理,如各种逻辑处理、复杂运算、统计、分析、数据报表等,业务层的代码往往是整个功能的核心
- 3)将计算好的数据返回给表现层
- 持久层:又称数据层、dao层等;数据主要的功能就是查询数据库,负责采用什么技术查询数据库,如何查询,将业务层传递过来的参数变成SQL语句等;
- 1)接受业务传递的参数
- 2)查询数据库
- 3)将结果返回给业务层
6.4 MVC中的三层
- 问:我们的JavaWeb开发使用哪种架构?既用MVC,又用三层结构
组成 | 说明 | JavaWeb中的实现 |
---|---|---|
Model | 模型层: 处理业务逻辑代码、处理数据库访问代码 | 业务层、持久层 |
View | 表示层: 处理直接面向客户 | 通过JSP、HTML、CSS、JS、JSTL、EL |
Contoller | 控制器: 1)整个项目控制核心,所有的用户请求首先要到达控制器 2)由控制器去控制调用哪个业务功能 3)调用完毕以后,由控制器决定将哪个视图展现给最终的用户。 | Servlet |
MVC和三层架构很相似,可以这样说:在三层架构中有MVC的影子,MVC中也能看到三层架构的影子;确切的来说,MVC偏向软件的一个设计思想,三层架构更多的是落实到了代码层面;
不管是三层架构还是MVC都只是软件设计的一种思想(架构),不受编程语言限制;
七、综合案例:完成用户显示列表案例
7.1 案例需求
使用三层架构和MVC模式开发代码,完成用户显示列表功能。
7.2 案例效果
7.3 实现步骤
7.3.1 执行SQL语句
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(11) NOT NULL COMMENT 'ID',
`username` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用户名',
`password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '密码',
`gender` int(11) NULL DEFAULT NULL COMMENT '性别 0:男 1女',
`age` int(11) NULL DEFAULT NULL COMMENT '年龄',
`address` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '籍贯',
PRIMARY KEY (`id`) USING BTREE
) ;
INSERT INTO `user` VALUES (1, 'admin', '111', 0, 20, '广东潮州');
INSERT INTO `user` VALUES (2, 'root', '222', 1, 22, '云南大理');
INSERT INTO `user` VALUES (3, 'zhangsan', '333', 1, 19, '江西萍乡');
INSERT INTO `user` VALUES (4, 'lisi', '444', 0, 23, '湖南郴州');
7.3.2 导入jar包、配置文件、实体类和工具类
1)导入jar包
2)准备配置文件
jdbc.properties:
username=root
password=admin
url=jdbc:mysql://localhost:3306/test
driverClassName=com.mysql.jdbc.Driver
3)实体类
public class User {
private Integer id;
private String username;
private String password;
private Integer gender;
private Integer age;
private String address;
}
7.3.3 数据源工具类
package com.dfbz.utils;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
/**
* 数据源的工具类
*/
public class DataSourceUtils {
private static DataSource ds;
/**
* 在静态代码块中创建数据源对象
*/
static {
//创建属性对象
Properties info = new Properties();
try (//得到输入流
InputStream in = DataSourceUtils.class.getResourceAsStream("/jdbc.properties");) {
//加载到属性对象中
info.load(in);
ds = DruidDataSourceFactory.createDataSource(info);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 得到数据源
*/
public static DataSource getDataSource() {
return ds;
}
/**
* 从连接池中得到连接对象
*/
public static Connection getConnection() {
try {
return ds.getConnection();
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
/**
* 释放资源
*/
public static void close(Connection conn, Statement stmt, ResultSet rs) {
//关闭结果集
if (rs!=null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
//关闭语句对象
if (stmt!=null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
//关闭连接对象
if (conn!=null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
/**
* 关闭连接
*/
public static void close(Connection conn, Statement stmt) {
close(conn, stmt, null);
}
}
7.3.4 验证码类
package com.dfbz.utils;
import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Date;
import java.util.Random;
@WebServlet("/generateCode")
public class GenerateImageCodeServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private static final char[] CH = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890".toCharArray();
private static final int IMAGE_WIDTH = 73;
private static final int IMAGE_HEIGHT = 28;
private static final int LINE_NUM = 30;
private static final int RANDOM_NUM = 4;
Random random = new Random();
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("image/jpg");//设置相应类型,告诉浏览器输出的内容为图片
response.setHeader("Pragma", "No-cache");//设置响应头信息,告诉浏览器不要缓存此内容
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expire", new Date().getTime());
BufferedImage bi = new BufferedImage(IMAGE_WIDTH, IMAGE_HEIGHT, BufferedImage.TYPE_INT_BGR);
Graphics g = bi.getGraphics();
g.fillRect(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT);
g.setColor(getRandomColor(110, 133));
g.setFont(new Font("Times New Roman", Font.ROMAN_BASELINE, 18));
// 绘制干扰线
for (int i = 1; i <= LINE_NUM; i++) {
int x = random.nextInt(IMAGE_WIDTH);
int y = random.nextInt(IMAGE_HEIGHT);
int xl = random.nextInt(13);
int yl = random.nextInt(15);
g.drawLine(x, y, x + xl, y + yl);
}
// 绘制随机字符
StringBuilder sb = new StringBuilder();
String str = null;
for (int i = 0; i < RANDOM_NUM; i++) {
g.setFont(new Font("Fixedsys", Font.CENTER_BASELINE, 18));
g.setColor(new Color(random.nextInt(101), random.nextInt(111), random.nextInt(121)));
str = CH[random.nextInt(CH.length)] + "";
g.drawString(str, 13 * i, 16);
g.translate(random.nextInt(3), random.nextInt(3));
sb.append(str);
}
g.dispose();
request.getSession().setAttribute("safeCode", sb.toString());
ImageIO.write(bi, "JPG", response.getOutputStream());
}
/**
* 获得颜色
*/
private Color getRandomColor(int fc, int bc) {
if (fc > 255)
fc = 255;
if (bc > 255)
bc = 255;
int r = fc + random.nextInt(bc - fc - 16);
int g = fc + random.nextInt(bc - fc - 14);
int b = fc + random.nextInt(bc - fc - 18);
return new Color(r, g, b);
}
}
7.3.5 用户登录
7.3.5.1 登录页面
login.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户登录</title>
</head>
<body>
<form action="login" method="post">
用户名:<input type="text" name="username">
<hr>
密码:<input type="password" name="password">
<hr>
验证码:<input type="text" name="checkCode"> <a href="javascript:location.reload()"><img src="generateCode" alt=""></a>
<hr>
<input type="submit" value="登录">
<hr>
<h3>${error}</h3>
</form>
</body>
</html>
7.3.5.2 LoginServlet:
package com.dfbz.controller;
import com.dfbz.service.UserService;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
/**
* 控制器层
*/
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
// 只要有关于user的业务都交给我来处理
private UserService userService = new UserService();
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1. 接受前端提交的参数
String username = request.getParameter("username");
String password = request.getParameter("password");
String checkCode = request.getParameter("checkCode");
// 对比验证码
HttpSession session = request.getSession();
// 服务器端的验证码
Object safeCode = session.getAttribute("safeCode");
if (!checkCode.equals(safeCode)) {
// 说明验证码错误了!
request.setAttribute("error","验证码错误");
request.getRequestDispatcher("/login.jsp").forward(request, response);
return;
}
// 2. 调用业务层进行业务处理
// 调用login业务方法;根据用户名和密码查询数据库的条数
Integer count = userService.login(username, password);
// 3. 根据业务层返回的信息来决定跳转到哪个视图
if (count <= 0) {
// 没有查询到
// 说明用户名或密码错误
// 设置前端的提示语句
request.setAttribute("error","用户名或密码错误");
request.getRequestDispatcher("/login.jsp").forward(request, response);
return;
}
session.setAttribute("loginUser",username);
// 查询到了 咱们应该是跳转到后台的servlet进行列表的查询,然后由这个servlet转发到list.jsp
response.sendRedirect(request.getContextPath()+"/list");
}
}
7.3.5.3 UserService:
package com.dfbz.service;
import com.dfbz.dao.UserDao;
import com.dfbz.entity.User;
import java.util.List;
/*
业务逻辑层:专门负责处理user的业务
*/
public class UserService {
// 只要是要查询user的数据库信息都交给我来处理
private UserDao userDao = new UserDao();
/**
* 用户登录方法:根据用户名和密码查询是否有这一条记录
*
* @param username
* @param password
* @return
*/
public Integer login(String username, String password) {
Integer count = userDao.countByUsernameAndPassword(username, password);
return count;
}
}
7.3.5.4 UserDao
package com.dfbz.dao;
import com.dfbz.entity.User;
import com.dfbz.utils.DataSourceUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
/**
* 数据层:负责user类型的业务的SQL语句编写
*/
public class UserDao {
/**
* 根据用户名和密码查询数据库有多少条记录
*
* @param username
* @param password
* @return
*/
public Integer countByUsernameAndPassword(String username, String password) {
try {
// 获取数据库连接
Connection connection = DataSourceUtils.getConnection();
// 创建预定义SQL对象
PreparedStatement ps = connection.prepareStatement("select count(id) from user where username=? and password=?");
ps.setString(1, username);
ps.setString(2, password);
// 获取结果集
ResultSet rs = ps.executeQuery();
Integer count = 0;
if (rs.next()) {
count = rs.getInt(1);
}
return count;
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return null;
}
}
7.3.6 用户列表
7.3.6.1 列表页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<!-- 网页使用的语言 -->
<html lang="zh-CN">
<head>
<!-- 指定字符集 -->
<meta charset="utf-8">
<!-- 使用Edge最新的浏览器的渲染方式 -->
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
<title>用户列表</title>
<style type="text/css">
td, th {
text-align: center;
}
</style>
</head>
<body>
<div>
<h2 style="color:red;text-align: center">欢迎您:${loginUser.username}</h2>
<h3 style="text-align: center">通讯录:</h3>
<table border="1" align="center" width="500" height="200">
<tr style="background-color:#c4c7ce;">
<th>ID</th>
<th>用户名</th>
<th>密码</th>
<th>性别</th>
<th>年龄</th>
<th>地址</th>
</tr>
<%--使用forEach遍历元素--%>
<c:forEach items="${userList}" var="user">
<tr>
<td>${user.id}</td>
<td>${user.username}</td>
<td>${user.password}</td>
<td>${user.gender==0?'男':'女'}</td>
<td>${user.age}</td>
<td>${user.address}</td>
</tr>
</c:forEach>
</table>
</div>
</body>
</html>
7.3.6.2 ListServlet:
package com.dfbz.controller;
import com.dfbz.entity.User;
import com.dfbz.service.UserService;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.List;
@WebServlet("/list")
public class ListServlet extends HttpServlet {
// 用于处理user的业务
private UserService userService = new UserService();
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession();
Object loginUser = session.getAttribute("loginUser");
if(loginUser == null){
// 说明用户还未登录,重定向到登录页面
response.sendRedirect(request.getContextPath()+"/login.jsp");
// 要结束方法的运行,要不然重定向完毕后面的代码依旧执行
return;
}
// 查询所有的用户详情
List<User> userList = userService.findAll();
request.setAttribute("userList", userList);
// 跳转到列表页面
request.getRequestDispatcher("/list.jsp").forward(request, response);
}
}
7.3.6.3 UserService:
/**
* 查询数据库中的所有用户
* @return
*/
public List<User> findAll() {
List<User> userList=userDao.findAll();
return userList;
}
7.3.6.4 UserDao
/**
* 查询数据库中的所有用户
*
* @return
*/
public List<User> findAll() {
try {
// 获取数据库连接
Connection connection = DataSourceUtils.getConnection();
// 获取预定于SQL语句对象
PreparedStatement ps = connection.prepareStatement("select * from user");
// 查询结果集
ResultSet rs = ps.executeQuery();
List<User> userList = new ArrayList<>();
while (rs.next()) {
Integer id = rs.getInt("id");
String dbUsername = rs.getString("username");
String password = rs.getString("password");
Integer gender = rs.getInt("gender");
Integer age = rs.getInt("age");
String address = rs.getString("address");
userList.add(new User(id, dbUsername, password, gender, age, address));
}
return userList;
} catch (SQLException throwables) {
throwables.printStackTrace();
}
// 如果出现异常返回null
return null;
}