JavaEE
JavaEE 开发技术的简介
产生
为了满足开发多层体系结构的企业级应用的需求,Java公司的创始人Sun公司在早期的J2SE(Java 2 Platform Standard Edition)基础上,针对企业级应用的各种需求,提出了J2EE(Java 2 Plantform Enterprise Edition).
特点
定义:泛指那些为大型组织部门创建的应用程序。注:并不是特指为企业开发的应用软件。
企业级应用程序一般具有以下特点:
1)分布式:通过局域网运行在一个组织内部,或通过Internet连接分布在世界各地的部门或用户。
2)高速反应:不断地改变业务规则来适应社会信息的高速变化。
3)安全性:不但要实现应用系统的正常操作和运转,还必须保证系统运行的安全可靠。
4)可扩展性:充分考虑用户群体膨胀给应用带来的性能上的扩展需求。
5)集成化:对老的系统进行集成。
Java的体系结构
Servlet
基础
- 什么是servlet
Servlet(Server Applet),全称Java Servlet,未有中文译文。是用Java编写的服务器端程序。其主要功能在于交互式地浏览和修改数据,生成动态Web内容。狭义的Servlet是指Java语言实现的一个接口,广义的Servlet是指任何实现了这个Servlet接口的类,一般情况下,人们将Servlet理解为后者。Servlet运行于支持Java的应用服务器中。从实现上讲,Servlet可以响应任何类型的请求,但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务器。 - 主要内容
- 请求响应
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-go7SrAEb-1608173515354)(C:\Users\le\AppData\Roaming\Typora\typora-user-images\image-20201211152606659.png)]
响应的完整流程
- 客户端发送请求,tomcat通过请求头获知浏览器访问的是哪个主机
- 再通过请求⾏获取访问的是哪个⼀个web应⽤
- 再通过请求⾏中的请求路径获知访问的是哪个资源
- 通过获取的资源路径在配置中匹配到真实的路径,
- 服务器会创建servlet对象,(如果是第⼀次访问时,创建servlet实例,并调⽤init⽅法进⾏初始化
操作) - 调⽤service(request, response)⽅法来处理请求和响应的操作
- 调⽤service完毕后返回服务器 由服务器讲response缓冲区的数据取出,以http响应的格式发送给
浏览器
- 生命周期
其中,init( ),service( ),destroy( )是Servlet生命周期的方法。代表了Servlet从“出生”到“工作”再到“死亡 ”的过程。Servlet容器(例如TomCat)会根据下面的规则来调用这三个方法:
- init( ),当Servlet第一次被请求时,Servlet容器就会开始调用这个方法来初始化一个Servlet对象出来,但是这个方法在后续请求中不会在被Servlet容器调用,就像人只能“出生”一次一样。我们可以利用init( )方法来执行相应的初始化工作。调用这个方法时,Servlet容器会传入一个ServletConfig对象进来从而对Servlet对象进行初始化。
- service( )方法,每当请求Servlet时,Servlet容器就会调用这个方法。就像人一样,需要不停的接受老板的指令并且“工作”。第一次请求时,Servlet容器会先调用init( )方法初始化一个Servlet对象出来,然后会调用它的service( )方法进行工作,但在后续的请求中,Servlet容器只会调用service方法了。
- destory,当要销毁Servlet时,Servlet容器就会调用这个方法,就如人一样,到时期了就得死亡。在卸载应用程序或者关闭Servlet容器时,就会发生这种情况,一般在这个方法中会写一些清除代码。
配置
- web.xml 中Servlet的注解
<servlet>
<!-- servlet的内部名称,自定义 -->
<servlet-name>DemoAction</servlet-name>
<!-- servlet的类全名:包名+类名 -->
<servlet-class>com.uplooking.controller.DemoAction</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- servlet的映射配置 -->
<servlet-mapping>
<!-- servlet的内部名称,一定要和上面的内部名称保持一致 -->
<servlet-name>DemoAction</servlet-name>
<!-- servlet的映射路径(访问serclet的名称 -->
<url-pattern>/DemoAction</url-pattern>
</servlet-mapping>
- 首先,从浏览器中发送请求,是从当前工程中的路径与servlet-mapping标签中的url-pattern的标签值进行匹配。
- 根据这个映射值,找到servlet-mapping标签中的servlet-name的值与servlet标签中的servlet-name进行匹配
- 匹配到以后,找到servlet标签中的servlet-class标签中对应servlet类的src文件夹下的全路径。
- 从而调用并执行相应的servlet类。
# Init 初始化参数
1 <init-param>
2 <param-name>abc</param-name>
3 <param-value>123</param-value>
4 </init-param>
# 一个Servlet可以配置一个或多个初始化参数。
# 在应用程序中,可以使用Servlet的getInitParameter(String param)来读取初始化param对应的参数;若要读取所有的初始化参数名称,则可以使用getInitParameterNames()方法获得所有的参数名称,类型为枚举(Enumeration)。
//获取所有初始化参数
Enumeration<String> strs=this.getInitParameterNames();
while(strs.hasMoreElements()) {
str=strs.nextElement();
System.out.println(str+" "+this.getInitParameter(str));
//-->abc 123
//-->aaa 111
}
# 这些初始化参数也可以由ServletConfig对象获取,Servlet提供getServletConfig()方法提供ServletConfig对象。由ServletConfig获取初始化参数和由Servlet获取初始化参数的方法是一样的。
//两种调用getInitParameter的情况,视情况而定
//this是指ServletConfig的对象config
String str=this.getInitParameter("abc"); //第一种
String str=config.getInitParameter("abc");//第二种
上下文参数
1 <context-param>
2 <param-name>root</param-name>
3 <param-value>123</param-value>
4 </context-param>
获取context-param需要使用ServletContext对象。ServletContext对象可以通过在Servlet中的getServletConfig().getServletContext()方法获得。得到ServletContext对象后,使用getInitParameter(String param)方法获取名为param的参数值,通过getInitParameterNames()获取所有的context-param名称。
ServletContext context=this.getServletContext();
String root=context.getInitParameter("root");
System.out.println("root="+root);
- 注解访问
只需在对应的servlet类中添加servlet注解即可,从浏览器发送请求时,是用当前“工程”下的路径,会去对应servlet类的上面寻找是否存在对应url名称的@webServlet注解,存在的话,调用并执行对应的servlet类。
1 @WebServlet("/DemoAction")
2 public class DemoAction extends HttpServlet{
3 }
对请求的处理方式
HttpServlet抽象类
- HttpServlet抽象类是继承于GenericServlet抽象类而来的。使用HttpServlet抽象类时,还需要借助分别代表Servlet请求和Servlet响应的HttpServletRequest和HttpServletResponse对象。
- HttpServletRequest接口扩展于javax.servlet.ServletRequest接口,HttpServletResponse接口扩展于javax.servlet.servletResponse接口。
- 接下来我们再看看service方法是如何工作的,我们会发现在service方法中还是没有任何的服务逻辑,但是却在解析HttpServletRequest中的方法参数,并调用以下方法之一:doGet,doPost,doHead,doPut,doTrace,doOptions和doDelete。这7种方法中,每一种方法都表示一个Http方法。doGet和doPost是最常用的。所以,如果我们需要实现具体的服务逻辑,不再需要覆盖service方法了,只需要覆盖doGet或者doPost就好了。
HttpServletRequest接口
HttpServletRequest 表示Http环境的Servlet请求。它扩展于javax.servlet.ServletRequest接口,并添加了几个方法。
String getContextPath();//返回请求上下文的请求URI部分
Cookie[] getCookies();//返回一个cookie对象数组
String getHeader(String var1);//返回指定HTTP标题的值
String getMethod();//返回生成这个请求HTTP的方法名称
String getQueryString();//返回请求URL中的查询字符串
HttpSession getSession();//返回与这个请求相关的会话对象
HttpServletResponse接口
在Service API中,定义了一个HttpServletResponse接口,它继承自ServletResponse接口,专门用来封装HTTP响应消息。 由于HTTP请求消息分为状态行,响应消息头,响应消息体三部分,因此,在HttpServletResponse接口中定义了向客户端发送响应状态码,响应消息头,响应消息体的方法
通过Response设置响应
void addCookie(Cookie var1);//给这个响应添加一个cookie
void addHeader(String var1, String var2);//给这个请求添加一个响应头
void sendRedirect(String var1) throws IOException;//发送一条响应码,讲浏览器跳转到指定的位置
void setStatus(int var1);//设置响应行的状态码
Response的乱码问题
- response.setCharacterEncoding(“utf-8”);
- response.setHeader(“Content-type”,"text/html;charset=utf-8);
- response.setContentType(“text/html;charset=utf-8”);
会话管理
Session介绍
服务器会为每个浏览器 创建单独Session对象,Session对象用来保存与对应浏览器相关会话数据
Session原理
1、当客户端访问服务器,第一次 request.getSession() API得到执行,随机创建Session对象,为对象创建唯一编号 id
2、服务器会将创建Session 的编号 id 以Cookie形式 发送给客户端
3、客户端接收 session的编号,保存起来(会话级别、持久级别)
4、客户端下次访问服务器,因为cookie中含有session的id ,会自动携带session的id
5、服务器端,从cookie中获得session的id,并且request.getSession()时,根据session的id查找到服务器端对应Session对象
Session的配置
服务器有着N个session,浏览器关闭后服务器端的session不会立马删除,只是失去关联,而是等30分钟后清除(很占内存资源,一个项目里面不要过多地使用session);可以在web.xml文件中设置超时时间
<session-config>
<session-timeout>30<.session-timeout> # 设置过期时间
</session-config>
# java 实现session
HttpSession session = request.getSession();
//将数据存储到session中
session.setAttribute("data", "孤傲苍狼");
//获取session的Id
String sessionId = session.getId();
//判断session是不是新创建的
if (session.isNew()) {
response.getWriter().print("session创建成功,session的id是:"+sessionId);
}else {
response.getWriter().print("服务器已经存在该session了,session的id是:"+sessionId);
}
Session和Cookie的区别
- session是服务端存储,cookie是浏览器端存储
- Cookie是把用户的数据写给用户的浏览器。
- Session技术把用户的数据写到用户独占的session中。
- Session对象由服务器创建,开发人员可以调用request对象的getSession方法得到session对象。
重定向和请求转发
重定向
response.sendRedirect()
是一种客户端行文,从本质上讲等同于两次请求,前一次请求对象不会保存,地址栏的URL地址会改变。
请求转发
request.getRequestDispatcher().forward(request,response)
是一种服务器的行为,客户端只有一次请求,服务器端转发后会将请求对象保存,地址栏中的URL地址不会改变,得到响应后服务器端再将响应发给客户端;
两者的区别
- 重定向访问服务器两次,转发只访问服务器一次
- 重定向可以看见目标页面的url,转发只能看见第一访问的页面的url,以后的工作都是服务器来做的
- 重定向跳转后必须加上return,也不然页面跳转了,但是还会执行跳转后的语句,转发是执行了跳转页面,下面的代码就不会在执行了
- 在request级别使用信息共享,使用重定向必然出错,数据会丢失
- 重定向可以访问自己web应用资源以外的资源
补充
JavaWeb的四大作用域为:PageContext,ServletRequest,HttpSession,ServletContext;
PageContext域
生命周期
当对JSP的请求时开始,当响应结束时销毁。
作用范围
整个JSP页面,是四大作用域中最小的一个,即超过这个页面就不能够使用了。(所以使用pageContext对象向其它页面传递参数是不可能的.)
作用
(1)获取其它八大隐式对象,可以认为是一个入口对象。
(2)获取其所有域中的数据
pageContext 操作所有域中属性的方法
public java.lang.Object getAttribute(java.lang.String name,intscope)
public void setAttribute(java.lang.String name, java.lang.Objectvalue,int scope)
public void removeAttribute(java.lang.String name,int scope)
pageContext 中代表域的常量
PageContext.APPLICATION_SCOPE
PageContext.SESSION_SCOPE
PageContext.REQUEST_SCOPE
PageContext.PAGE_SCOPE
findAttribute方法,在四大域中搜寻属性,搜寻的顺序是page域、request域、session域、application域,
从小域到大域开始搜索,如果搜索到就直接获取该值,如果所有域中都找不到,返回一个null(与el表达式不同,此处返回null,对网页是不友好的)
(3) 跳转到其他资源,其身上提供了forward和include方法,简化重定向和转发的操作。
ServletRequest域
生命周期
在service 方法调用前由服务器创建,传入service方法。整个请求结束,request生命结束。
作用范围
整个请求链(请求转发也存在)
作用
在整个请求链中共享数据。最常用到:在Servlet 中处理好的数据交给Jsp显示,此时参数就可以放置在Request域中带过去。
HttpSession域
生命周期
在第一次调用 request.getSession() 方法时,服务器会检查是否已经有对应的session,如果没有就在内存 中创建一个session并返回。
当一段时间内session没有被使用(默认为30分钟),则服务器会销毁该session。
如果服务器非正常关闭(强行关闭),没有到期的session也会跟着销毁。
如果调用session提供的invalidate(),可以立即销毁session。
注意: 服务器正常关闭,再启动,Session对象会进行钝化和活化操作。同时如果服务器钝化的时间在session 默认销毁时间之内,则活化后session还是存在的。否则Session不存在。如果JavaBean 数据在session钝化时,没有实现Serializable 则当Session活化时,会消失。
作用范围
一次会话。
作用
- 可以防止表单二次提交
ServletContext域
生命周期
当Web应用被加载进容器时创建代表整个web应用的ServletContext对象,当服务器关闭或Web应用被移除时,ServletContext对象跟着销毁。
作用范围
整个Web应用。
作用
- 在不同Servlet 之间转发
- 读取资源文件。
JSP
什么是JSP?
基于java平台的动态web页面技术,利用这种技术,可以实现html语言和Java服务端语法元素的融合,能够是页面的表示逻辑与服务端运行的代码分离,便于程序的维护。
为什么要使用JSP?
对web开发者来说,引入jsp,可以把动态网页的表示逻辑从臃肿的Servlet代码中分离出来,即实现web应有的前后端分离,有利于程序的维护
JSP三大指令
Page
<%@page language=”java” info=”xxx”…%>
- pageEncoding和contentType:
pageEncoding:它指定当前jsp页面的编码,只要不说谎,就不会有乱码!在服务器要把jsp编译成.java时需要使用pageEncoding!
contentType:它表示添加一个响应头:Content-Type!等同与response.setContentType(“text/html;charset=utf-8”);
如果两个属性只提供一个,那么另一个的默认值为设置那一个。
如果两个属性都没有设置,那么默认为iso- import:导包!可以出现多次
- errorPage和isErrorPage
errorPage:当前页面如果抛出异常,那么要转发到哪一个页面,由errorPage来指定
isErrorPage:它指定当前页面是否为处理错误的页面!当该属性为true时,这个页面会设置状态码为500!而且这个页面可以使用9大内置对象中的exception
<error-page>有两种使用方式:
<error-code>和<location>子元素;
<exception-type>和<location>子元素;
其中<error-code>是指定响应码;<location>指定转发的页面;<exception-type>是指定抛出的异常类型。
eg:
<error-page>
<error-code>404</error-code>
<location>/error/errorPage.jsp</location>
</error-page>
<error-page>
<exception-type>java.lang.RuntimeException</exception-type>
<location>/index.jsp</location>
</error-page>
- autoFlush和buffer
autoFlush:指定jsp的输出流缓冲区满时,是否自动刷新!默认为true,如果为false,那么在缓冲区满时抛出异常!
buffer:指定缓冲区大小,默认为8kb,通常不需要修改!
- isELIgnored:是否忽略el表达式,默认值为false,不忽略,即支持!
- (以下了解即可):
language:指定当前jsp编译后的语言类型,默认值为java。
info:信息!
isThreadSafe:当前的jsp是否支持并发访问!
session:当前页面是否支持session,如果为false,那么当前页面就没有session这个内置对象!
extends:让jsp生成的servlet去继承该属性指定的类!
include -> 静态包含
- 与RequestDispatcher的include()方法的功能相似!
- <<%@include%> >它是在jsp编译成java文件时完成的!他们共同生成一个java(就是一个servlet)文件,然后再生成一个class!
- RequestDispatcher的include()是一个方法,包含和被包含的是两个servlet,即两个.class!他们只是把响应的内容在运行时合并了!
- 作用:把页面分解了,使用包含的方式组合在一起,这样一个页面中不变的部分,就是一个独立jsp,而我们只需要处理变化的页面。
taglib -> 导入标签库
两个属性
prefix:指定标签库在本页面中的前缀!由我们自己来起名称!
uri: 指定标签库的位置!
<%@taglib prefix=”s” uri=”/struts-tags”%> 前缀的用法 ``
九大内置对象
- 在jsp中无需声明即可直接使用的9个对象
- out(JspWriter):等同与response.getWriter(),用来向客户端发送文本数据;
- config(ServletConfig):对应“真身”中的ServletConfig;
- page(当前JSP的真身类型):当前JSP页面的“this”,即当前对象,引用为Object类型;
- pageContext(PageContext):页面上下文对象,它是最后一个没讲的域对象;
- exception(Throwable):只有在错误页面中可以使用这个对象;
- request(HttpServletRequest):即HttpServletRequest类的对象;
- response(HttpServletResponse):即HttpServletResponse类的对象;
- application(ServletContext):即ServletContext类的对象;
- session(HttpSession):即HttpSession类的对象,不是每个JSP页面中都可以使用,如果在某个JSP页面中设置<%@page session=”false”%>,说明这个页面不能使用session。
- pageContext(一个顶9个!)
- Servlet中有三大域,而JSP中有四大域!
ServletContext:整个应用程序
session:整个会话(一个会话中只有一个用户)
request:一个请求链!
pageContext:一个jsp页面!这个域是在当前jsp页面和当前jsp页面中使用的标签之间共享数据!
域对象
代理其他域:pageContext.setAttribute(“xxx”, “XXX”, PageContext.SESSION_SCOPE);
全域查找:pageContext.findAttribute(“xxx”);从小到大,依赖查找!
获取其他8个内置对象:
JSP动作标签
动作标签是由tomcat(服务器)来解释执行!而html标签由浏览器来执行!
<jsp:include>
例如:
<jsp:include page="xxx"/>
用来包含指定的页面。假如有两个jsp. 分别为a.jsp和b.jsp,他们分别编码成Servlet,然后在执行Servlet时才会执行包含过程。这也是include指令与include标签的区别。
- 注意:
<jsp:include page="<%myfile%>">
这是可以的!因为include指令是在执行时才完成的包含,在执行时已经可以确定myfile这个变量的值。
- 该标签内部使用的是RequestDispatcher#include()方法完成的包含
<jsp:forward>
例如:
<jsp:forward page="xxxx"> 用来转发到指定页面 例如在a.jsp中存在如下内容:<jsp:forward page="b.jsp"> ,a.jsp中的内容不会显示在浏览器上,而只是显示b.jsp的内容。而且在<jsp:forward>标签下面的内容不会被执行。
<jsp:param> 该标签是和的子标签,用来向其他页面传递参数
# 示例
<jsp:include page="/b.jsp">
<jsp:param value="zhangSan" name="username"/>
</jsp:include>
# 在b.jsp中可以使用request.getParameter(“username”)来获取参数值。
EL表达式
什么是EL表达式
EL表达式的语法,都是用“${ }”表示的。
关于EL表达式和使用Java代码的区别:
在Servlet中:
request.setAttribute("username","zhangsan");
request.setAttribute("password","123");
// 在JSP中使用Java脚本:
用户名:<%=request.getAttribute("username")%><br />
密码: <%=request.getAttribute("password")%>
// 使用EL表达式
用户名:${username}<br />
密码: ${password}
EL表达式不仅能获取Servlet中存储的数据,也能简化JSP中的代码量,使程序简单易维护,另外,当域对象里面的值不存在时,使用EL表达式获取域对象里面的值返回空字符串;而使用Java脚本方式获取,返回值是null,会报空指针异常。
EL中的运算符
点运算符(.)
EL表达式中的点运算符,用于访问JSP页面中某些对象的属性,如JavaBean对象、List集合、Array数组等。
${user.username}
方括号([])
EL表达式中的方括号运算符与点运算符的功能相同,都用于访问JSP页面中某些对象的属性。当获取的属性名中包含一些特殊符号,如“_”或“-”“?”等并非数字或字母的符号,就只能使用方括号运算符来访问该属性。
${user[“user_name”]}
- 点运算符和方括号运算符在某种情况下可以互换,如
${user.username}
等价于${user["username"]}
- 方括号运算符还可以访问List集合或数组中指定索引的某个元素,如表达式${users[0]}用于访问集合或数组中第一个元素。在这种情况下,只能使用方括号运算符,不能使用点运算符。
- 方括号运算符和点运算符可以相互结合使用,如
${users[0].username}
,表示访问集合或者数组中的第一个元素的username属性。
算术运算符
算数运算符 | 说明 | 算术表达式 | 结果 |
+ | 加 |
| 2 |
- | 减 |
| 0 |
* | 乘 |
| 1 |
/ (或div) | 除 |
| 1 |
% (或mod) | 取余(取模) |
| 0 |
比较运算符
EL表达式中的比较运算符用于比较两个操作数的大小,操作数可以是各种常量、EL表达式、EL变量,所有的运算执行结果都是布尔类型。
比较运算符 | 说明 | 算术表达式 | 结果 |
==(或eq) | 等于 |
| false |
!=(或ne) | 不等于 |
| true |
<(或lt) | 小于 |
| false |
>(或gt) | 大于 |
| true |
<=(或le) | 小于等于 |
| false |
>=(或ge) | 大于等于 |
| true |
逻辑运算符
逻辑运算符 | 说明 | 算术表达式 | 结果 |
| 逻辑与 |
| false |
| 逻辑或 |
| true |
| 逻辑非 |
| false |
empty运算符
EL表达式中的empty运算符用于判断某个对象是否为null或"",结果为布尔类型,其基本的语法格式如下:
${empty var}
- var变量不存在(没有定义),结果返回true
- var变量的值为null,结果返回true
- var变量引用集合(Set、Map、List)类型对象,并且在集合对象中不包含任何元素时,结果返回true
条件表达式
EL表达式中条件运算符用于执行某种条件判断,类似于Java中的if-else语句,其语法格式如下:
${A?B:C}
- var变量不存在(没有定义),结果返回true
- var变量的值为null,结果返回true
- var变量引用集合(Set、Map、List)类型对象,并且在集合对象中不包含任何元素时,结果返回true
”()“运算符
EL表达式中的圆括号用于改变其他运算符的优先级。
EL隐式对象
不需要new就能使用的对象,自带的对象
- 作用域访问对象(EL隐式对象):
pageScope、requestScope、sessionScope、applicationScope
- 参数访问对象
- JSP隐式对象
隐含对象名称 | 描述 |
| 对应于JSP页面中的pageContext对象 |
| 代表page域中用于保存属性的Map对象 |
| 代表request域中用于保存属性的Map对象 |
| 代表session域中用于保存属性的Map对象 |
| 代表application域中用于保存属性的Map对象 |
| 表示一个保存了所有请求参数的Map对象 |
| 表示一个保存了所有请求参数的Map对象,它对于某个请求参数,返回的是String类型数组 |
| 表示一个保存了所有HTTP请求头字段的Map对象 |
| 表示一个保存了所有HTTP请求头字段的Map对象,返回的是String类型数组 |
| 用来取得使用者的cookie值,cookie的类型是Map |
| 表示一个保存了所有Web应用初始化参数的Map对象 |
JavaBean
什么是JavaBean?
JavaBean是一个遵循特定写法的Java类,它通常具有如下特点:
- 这个Java类必须具有一个无参的构造函数
- 属性必须私有化。
- 私有化的属性必须通过public类型的方法暴露给其它程序,并且方法的命名也必须遵守一定的命名规范。
使用JavaBean的原因
程序中往往有重复使用的段落,JavaBean就是为了能够重复使用而设计的程序段落,而且这些段落并不只服务于某一个程序,而且每个JavaBean都具有特定功能,当需要这个功能的时候就可以调用相应的JavaBean。从这个意义上来讲,JavaBean大大简化了程序的设计过程,也方便了其他程序的重复使用。
JavaBean传统应用于可视化领域,如AWT(窗口工具集)下的应用。而现在,JavaBean更多地应用于非可视化领域,同时,JavaBean在服务器端的应用也表现出强大的优势。非可视化的JavaBean可以很好地实现业务逻辑、控制逻辑和显示页面的分离,现在多用于后台处理,使得系统具有更好的健壮性和灵活性。JSP + JavaBean和JSP + JavaBean + Servlet成为当前开发Web应用的主流模式。
JavaBean的特点
- 易于维护、使用、编写
- 可实现代码的重用性
- 可移植性强,但只限于Java平台
- 便于传输,不限于本地还是网络
- 可以以其他部件的模式进行工作
JavaBean的属性
JavaBean的属性可以是任意类型,并且一个JavaBean可以有多个属性。每个属性通常都需要具有相应的setter、 getter方法,setter方法称为属性修改器,getter方法称为属性访问器。属性修改器必须以小写的set前缀开始,后跟属性名,且属性名的第一个字母要改为大写,例如,name属性的修改器名称为setName,password属性的修改器名称为setPassword。 属性访问器通常以小写的get前缀开始,后跟属性名,且属性名的第一个字母也要改为大写,例如,name属性的访问器名称为getName,password属性的访问器名称为getPassword。 一个JavaBean的某个属性也可以只有set方法或get方法,这样的属性通常也称之为只写、只读属性。
简单的JavaBean
public class SimpleBean{
private String name;
private int age;
public void setName(String name){
this.name = name;
}
public void setAge(int age){
this.age = age;
}
public String getName(){
return this.name;
}
public int getAge(){
return this.age;
}
}
Jsp中使用JavaBean
SP技术提供了三个关于JavaBean组件的动作元素,即JSP标签,它们分别为:
- <jsp:useBean>标签:用于在JSP页面中查找或实例化一个JavaBean组件。
- <jsp:setProperty>标签:用于在JSP页面中设置一个JavaBean组件的属性。
- <jsp:getProperty>标签:用于在JSP页面中获取一个JavaBean组件的属性。
<jsp:useBean>标签用于在指定的域范围内查找指定名称的JavaBean对象,如果存在则直接返回该JavaBean对象的引用,如果不存在则实例化一个新的JavaBean对象并将它以指定的名称存储到指定的域范围中。
常用语法:
<jsp:useBean id="beanName" class="package.class" scope="page|request|session|application"/>
"id"属性用于指定JavaBean实例对象的引用名称和其存储在域范围中的名称。
"class"属性用于指定JavaBean的完整类名(即必须带有包名)。
"scope"属性用于指定JavaBean实例对象所存储的域范围,其取值只能是page、request、session和application等四个值中的一个,其默认值是page。
<jsp:useBean>标签使用范例:
<%@ page contentType="text/html" pageEncoding="GBK"%>
<jsp:useBean id="simple" scope="page" class="blog.csdn.joywy.SimpleBean"/>
<html>
<head><title>欢迎来到望星空</title></head>
<body>
<%
simple.setName("Joywy");
simple.setAge(23);
%>
<h3>姓名:<%=simple.getName()%></h3>
<h3>年龄:<%=simple.getAge()%></h3>
</body>
</html>
<jsp:setProperty>标签使用范例:
<jsp:setProperty>标签用于设置和访问JavaBean对象的属性。
语法格式一:
<jsp:setProperty name="beanName" property="propertyName" value="string字符串"/>
语法格式二:
<jsp:setProperty name="beanName" property="propertyName" value="<%= expression %>" />
语法格式三:
<jsp:setProperty name="beanName" property="propertyName" param="parameterName"/>
语法格式四:
<jsp:setProperty name="beanName" property= "*" />
name属性用于指定JavaBean对象的名称。
property属性用于指定JavaBean实例对象的属性名。
value属性用于指定JavaBean对象的某个属性的值,value的值可以是字符串,也可以是表达式。为字符串时,该值会自动转化为JavaBean属性相应的类型,如果value的值是一个表达式,那么该表达式的计算结果必须与所要设置的JavaBean属性的类型一致。
param属性用于将JavaBean实例对象的某个属性值设置为一个请求参数值,该属性值同样会自动转换成要设置的JavaBean属性的类型。
<jsp:getProperty>标签使用范例:
<jsp:getProperty property="username" name="user1"/>
# 输出user1这个javaBean的username属性值
# 等同与
User user1 = (User)pageContext.getAttribute(“user1”);
out.print(user1.getUsername());
EL表达式
介绍:
1、EL简介
1)语法结构
${expression}
2)[]与.运算符
EL 提供.和[]两种运算符来存取数据。
当要存取的属性名称中包含一些特殊字符,如.或?等并非字母或数字的符号,就一定要使用 []。
例如:
${user.My-Name}应当改为${user["My-Name"] }
如果要动态取值时,就可以用[]来做,而.无法做到动态取值。例如:
${sessionScope.user[data]}中data 是一个变量
3)变量
EL存取变量数据的方法很简单,例如:${username}。它的意思是取出某一范围中名称为
username的变量。
因为我们并没有指定哪一个范围的username,所以它会依序从Page、Request、Session、
Application范围查找。
假如途中找到username,就直接回传,不再继续找下去,但是假如全部的范围都没有找到时,
就回传null。
属性范围在EL中的名称
Page PageScope
Request RequestScope
Session SessionScope
Application ApplicationScope
- EL:Expression Language,它是可以在JSP页面中直接使用的语言!
JSP页面也可以忽略EL:<@page isELIgnored=”true”%>
EL用来代替<%=…%>- EL 11个内置对象
EL可以输出的东西都在11个内置对象中!11个内置对象,其中10个是Map!pageContext不是map,它就是PageContext类型,1一个顶九个
- ${pageScope.xxx}、
- ${requestScope.xxx}、
- ${sessionScope.xxx}、
- ${applicationScope.xxx}
- param:对应参数,它是一个Map,其中key参数名,value是参数值,适用于单值的参数。
- paramValues:对应参数,它是一个Map,其中key参数名,value是多个参数值,适用于多值的参数。
- header:对应请求头,它是一个Map,其中key表示头名称,value是单个头值,适用于单值请求头
- headerValues:对应请求头,它是一个Map,其中key表示头名称,value是多个头值,适用于多值请求头
- initParam:获取``内的参数!
- cookie:
Map类型
,其中key是cookie的name,value是cookie对象。 ${cookie.username.value}- pageContext:它是PageContext类型!${pageContext.request.contextPath}
- EL操作四大域的内置对象:它们是Map类型
pageScope
requestScope
sessionScope
applicationScope
示例
${pageScope.user}:输出pageContext.getAttribute("user")
${requestScope.user}:输出request.getAttribute("user");
${sessionScope.user}:输出session.getAttribute("user");
${applicationScope.user}:输出application.getAttribute("user");
# initParam
initParam取得设定web站点的环境参数(Context)
例:一般的方法String userid = (String)application.getInitParameter("userid");
可以使用 ${initParam.userid}来取得名称为userid
# pageContext
pageContext取得其他有关用户要求或页面的详细信息。
${pageContext.request.queryString} 取得请求的参数字符串
${pageContext.request.requestURL} 取得请求的URL,但不包括请求之参数字符串
${pageContext.request.contextPath} 服务的web application 的名称
${pageContext.request.method} 取得HTTP 的方法(GET、POST)
${pageContext.request.protocol} 取得使用的协议(HTTP/1.1、HTTP/1.0)
${pageContext.request.remoteUser} 取得用户名称
${pageContext.request.remoteAddr } 取得用户的IP 地址
${pageContext.session.new} 判断session 是否为新的
${pageContext.session.id} 取得session 的ID
${pageContext.servletContext.serverInfo} 取得主机端的服务信息
EL函数
迭代标签
语法:<c:forEach items=“collection” var=“name” varStatus=“status” begin=“int“
end=”int” step=“int” >
//循环体</c:forEach>
说明:1)items:是集合,用EL表达式;
2)var:变量名,存放items
3)varStatus: 显示循环状态的变量
①index:从0开始;
②count:元素位置,从1开始;
③first:如果是第一个元素则显示true;
④last:如果是最后一个元素则显示true;
4)begin:循环的初始值(整型);
5)end: 循环结束 ;
6)step:步长,循环间隔的数值;
选择标签
IF / CHOOSE:
<c:if test="${var.index % 2 == 0}">
*
</c:if>
判定条件一般为一个EL表达式。
<c:if>并没有提供else子句,使用的时候可能有些不便,此时我们可以通过<c:choose>
tag来达到类似的目的:
<c:choose>
<c:when test="${var.index % 2 == 0}">
*
</c:when>
<c:otherwise>
!
</c:otherwise>
</c:choose>
类似Java 中的switch 语句,<c:choose>提供了复杂判定条件下的简化处理手法。其
中<c:when>子句类似case子句,可以出现多次。上面的代码,在奇数行时输出“*”号,
而偶数行时输出“!”。
<<c:param>>标签
说明:<c:param>标签用来传递参数给一个重定向或包含页面,它有以下属性属 性 描 述 是否
必须 缺省值
name 在request参数中设置的变量名 是 无
value 在request参数中设置的变量值 否 无
例子:
<c:redirect url="login.jsp">
<c:param name="id" value="888"/>
</c:redirect>
<c:redirect>标签
说明:标签将请求重新定向到另外一个页面,它有以下属性 属性 描 述 是否必须 缺省值
url url地址 是 无
context /后跟本地web应用程序的名字 否 当前应用程序
例子:
<c:redirect /'>http://www.yourname.com/login.jsp"/>
将请求重新定向到http://www.yourname.com/login.jsp页,相当于response.setRedirect
("http://www.yourname.com/login.jsp");
JSTL
- JSTL是apache对EL表达式的扩展
jstl标签库
- core:核心标签库,
- fmt:格式化标签库
- sql:数据库标签库,过时;
- xml:xml标签库,过时。
<<c:core>>
<c:out value=”aaa”/> 输出字符串aaa
<c:out value="${aaa}”/> 输出域属性aaa,其中与${aaa}相同
<c:out value="${aaa}” default=”xxx”/>如果${aaa}不存在,那么输出xxx字符串
<c:out value="${aaa}" escapeXml=”true”/>如果${aaa}中包含特殊字符,那么转义它。这可以防止javascript攻击
<<c:set>>
<c:set var=”a” value=”hello”/> 创建名为a,值为hello的域属性,范围:page
<c:set var=”a” value=”hello” scope=”session”/> 范围为session(page、request、session、application)
<<c:remove>>
<c:remove var=”a”/> 删除名为a的域属性
<c:remove var=”a” scope=”page”/> 删除page域中名为a的域属性
<<c:url>>
<c:url value=”/AServlet”/> 输出URL:/项目名/AServlet
<c:url value=”/AServlet” var=”url” scope=”page”/> 把生成的url保存到page域中,而不会输出
子标签:<c:param>,用来给url后面添加参数,例如:
<c:url value="/index.jsp">
<c:param name="username" value="张三"/> <!--可以对参数进行url编码!!-->
</c:url>
1
2
3
结果为:/day13_1/index.jsp?username=%ED%2C%3F%ED%2C%3F
1
* var:指定变量名,一旦添加了这个属性,那么url标签就不会再输出到页面,而是把生成url保存到域中。
* scope:它与var一起使用,用来保存url。
<<c:if>>
*<c:if test=”${条件}”> 当条件为true时执行标签体内容
hello
<<c:choose>>
<c:set var="score" value="${param.score }"/>
<c:choose>
<c:when test="${score > 100 || score < 0}">错误的分数:${score }</c:when>[if]
<c:when test="${score >= 90 }">A级</c:when>
<c:when test="${score >= 80 }">B级</c:when>
<c:when test="${score >= 70 }">C级</c:when>
<c:when test="${score >= 60 }">D级</c:when>
<c:otherwise>E级</c:otherwise>[else]
</c:choose>
<<c:forEcah>>
<c:forEach var="i" begin="1" end="10">
${i}
</c:forEach>
属性:
* var:循环变量
* begin:设置循环变量从几开始。
* end:设置循环变量到几结束。
* step:设置步长!等同与java中的i++,或i+=2。step默认为1
遍历集合或数组方式:
<%
String[] names = {"zhangSan", "liSi", "wangWu", "zhaoLiu"};
pageContext.setAttribute("ns", names);
%>
<c:forEach var="item" items="${ns }">
<c:out value="name: ${item }"/><br/>
</c:forEach>
遍历List
<%
List<String> names = new ArrayList<String>();
names.add("zhangSan");
names.add("liSi");
pageContext.setAttribute("ns", names);
%>
<c:forEach var="item" items="${ns }">
<c:out value="name: ${item }"/><br/>
</c:forEach>
遍历Map
<%
Map<String,String> stu = new LinkedHashMap<String,String>();
stu.put("number", "N_1001");
stu.put("name", "zhangSan");
pageContext.setAttribute("stu", stu);
%>
<c:forEach var="item" items="${stu }">
<c:out value="${item.key }: ${item.value }"/><br/>
</c:forEach>
- 循环状态
循环状态变量有如下属性:
* count:循环元素的个数
* index:循环元素的下标
* first:是否为第一个元素
* last:是否为最后一个元素
* current:当前元素
<c:forEach items="${list }" var="ele" varStatus="vs">
${vs.index} ${vs.count } ${vs.first } ${vs.last } ${vs.current }<br/>
</c:forEach>
JDBC
基本连接
# 加载JDBC驱动
class.forName(com.mysql.cj.jdbc.Driver);
# 建立连接
Connection conn = new DriverManager.getConnection("jdbc:mysql://localhost:8080/mysql?serverTimeZone=GMT&useSSL=true");
# 创建语句对象
String sql = "select * from user";
PreparedStatedment ps = cnn.preparedStatement(sql);
# 执行sql
ResultSet rs = ps.excuteQuery();
### excuteQuery() 返回的是ResultSet的对象
### excuteUpdate() 返回的是受到影响的行数
# 关闭连接 防止浪费资源
conn.close();
ps.close();
rs.close();
ResultSet
结果集类型,并发性和可持续性
基本的ResultSet
Statement st = conn.CreateStatement
ResultSet rs = Statement.excuteQuery(sqlStr);
可滚动的ResultSet类型
Statement st = conn.createStatement(int resultSetType, int resultSetConcurrency)
ResultSet rs = st.executeQuery(sqlStr)
遍历
// 获取的是list的列表
List<User> user = new ArrayList<>();
while(rs.next()){
// 通过获取元素遍历
User user = new User();
user.setId(res.getInt(1));
user.setAccount(res.getString("account"));
user.setPassword(res.getString("password"));
users.add(user);
}
数据库连接
传统的JDBC连接
public class JDBCUtilsDemo1{
static{
/**
*1. 加载驱动
*/
try {
Class.forName("com.mysql.jdbc.Driver"); //利用反射加载驱动
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* 2.建立连接
*/
public static Connection getConnection() {
try {
return DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf-8","root", "root");
} catch (SQLException e) {
throw newRuntimeException(e);
}
}
/**
* 关闭连接
* @param conn
* @param prep
* @param rs
*/
public static void close(Connection conn,PreparedStatementprep,ResultSet rs){
if(rs != null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
} finally{
rs = null;
}
}
if(prep != null){
try {
prep.close();
} catch (SQLException e) {
e.printStackTrace();
} finally{
prep = null;
}
}
if(conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
} finally{
conn = null;
}
}
}
/**
* 测试数据库连通性
*/
public static void main(String[] args) {
Connection conn=JDBCUtilsDemo1.getConnection();
System.out.println(conn);
JDBCUtilsDemo1.close(conn,null, null);
}
}
properties配置文件形式
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf-8
username=root
password=root
public class JDBCUtilsDemo2{
private static Properties prop;
static {
prop = new Properties();
try {
prop.load(JDBCUtilsDemo2.class.getClassLoader().getResourceAsStream(
"db.properties"));
Class.forName(prop.getProperty("driver"));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static Connection getConnection(Connection conn) {
if (conn==null) {
try {
conn=DriverManager.getConnection(prop.getProperty("url"),
prop.getProperty("username"),prop.getProperty("password"));
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
return conn;
}
public static void close(Connection conn,PreparedStatementprep,ResultSet rs){
if(rs != null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
} finally{
rs = null;
}
}
if(prep != null){
try {
prep.close();
} catch (SQLException e) {
e.printStackTrace();
} finally{
prep = null;
}
}
if(conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
} finally{
conn = null;
}
}
}
public static voidmain(String[] args) {
Connection conn = null;
conn=JDBCUtilsDemo2.getConnection(conn);
System.out.println(conn);
JDBCUtilsDemo2.close(conn,null, null);
}
}
数据源的配置 conf/context.xml
<Resource
name = "jdbc/news"
auth = "Container"
type = "javax.sql.DataSource"
maxActive = "100"
maxIdle = "30"
maxWait = "10000"
username = "root" # 用户
password = "123456" # 密码
driverClassName = "com.mysql.jdbc.Driver" # 数据库的驱动
url = "jdbc:mysql://localhost:3306/news"/>
// dao层的调用
public interface Dao {
public static DataSource geDataSource() throws DaoException{
DataSource dataSource=null;
try {
Context context=new InitialContext();
// xxx是context.xml中的resource中name的属性
dataSource=(DataSource)context.lookup("java:comp/env/xxx");
} catch (NamingException ex) {
DaoException exp=new DaoException("context.lookup调用异常:"+ex.getMessage());
throw exp;
}
return dataSource;
}
public default Connection getConnection() throws DaoException{
DataSource dataSource=Dao.geDataSource();
Connection conn=null;
try {
conn=dataSource.getConnection();
} catch (SQLException ex) {
DaoException exp=new DaoException("建立数据库连接失败:"+ex.getMessage());
throw exp;
}
return conn;
}
}
// 调用
xxxDao extends Dao
xxxDaoImpl implments xxxDao
// xxxDaoImpl中的代码
public boolean addManager(Manager manager) throws DaoException {
String sql="insert into manager values(?,?,?,?,?,?)";
Connection conn=this.getConnection();
boolean res=false;
try {
PreparedStatement psmt = conn.prepareStatement(sql);
psmt.setString(1, manager.getUsername());
psmt.setString(2, manager.getUserpwd());
psmt.setString(3,manager.getUsername());
LocalDate dt=LocalDate.now();
Date dt1=Date.valueOf(dt);
psmt.setDate(4, dt1);
psmt.setBoolean(5, manager.getIspass());
psmt.setInt(6, manager.getRole());
psmt.execute();
res = psmt.getUpdateCount()>0;
conn.close();
} catch (SQLException ex) {
throw new DaoException(ex.getMessage());
}
return res;
}
JSTL
使用
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
通用目的标签
<c:out>标签:输出作用域变量
<c:set>标签:定义作用域变量
<c:remove>标签:删除作用域变量
<c:catch>标签:
条件控制标签
<c:if>标签
<c:choose>标签
循环控制标签
<c:forEach>标签
### 示例
<c:forEach var="book" items="${books}" varStatus="status">
<tr>
<td>${book.id}</td>
<td>${book.title}</td>
<td>${book.author}</td>
<td>${book.publishTime}</td>
</tr>
</c:forEach>
JPA
什么是JPA
Java Persistence API:用于对象持久化的 API
Java EE 5.0 平台标准的 ORM 规范,使得应用程序以统一的方式访问持久层
JPA和Hibernate的关系
JPA 是 hibernate 的一个抽象(就像 JDBC 和 JDBC 驱动的关系):
- JPA 是规范:JPA 本质上就是一种 ORM 规范,不是ORM 框架 —— 因为 JPA 并未提供 ORM 实现,它只是制订了一些规范,提供了一些编程的 API 接口,但具体实现则由 ORM 厂商提供实现
- Hibernate 是实现:Hibernate 除了作为 ORM 框架之外,它也是一种 JPA 实现 从功能上来说,JPA 是 Hibernate 功能的一个子集
JPA的优势
- 标准化: 提供相同的 API,这保证了基于JPA 开发的企业应用能够经过少量的修改就能够在不同的 JPA 框架下运行。
- 简单易用,集成方便: JPA 的主要目标之一就是提供更加简单的编程模型,在 JPA 框架下创建实体和创建 Java 类一样简单,只需要使用 javax.persistence.Entity 进行注释;JPA 的框架和接口也都非常简单,
- 可媲美JDBC的查询能力: JPA的查询语言是面向对象的,JPA定义了独特的JPQL,而且能够支持批量更新和修改、JOIN、GROUP BY、HAVING 等通常只有 SQL 才能够提供的高级查询特性,甚至还能够支持子查询。
- 支持面向对象的高级特性: JPA 中能够支持面向对象的高级特性,如类之间的继承、多态和类之间的复杂关系,最大限度的使用面向对象的模型
基本注解
1. @Entity
@Entity 标注用于实体类声明语句之前,指出该Java 类为实体类,将映射到指定的数据库表。如声明一个实体类 Customer,它将映射到数据库中的 customer 表上。
2. @Table
当实体类与其映射的数据库表名不同名时需要使用 @Table 标注说明,该标注与 @Entity 标注并列使用,置于实体类声明语句之前,可写于单独语句行,也可与声明语句同行。
@Table 标注的常用选项是 name,用于指明数据库的表名
@Table(name="JPA_CUTOMERS")
@Entity
public class Customer {
}
3. @Id
@Id 标注用于声明一个实体类的属性映射为数据库的主键列。该属性通常置于属性声明语句之前,可与声明语句同行,也可写在单独行上。
@Id标注也可置于属性的getter方法之前。
@GeneratedValue(strategy=GenerationType.AUTO)
@Id
public Integer getId() {
return id;
}
4. @GeneratedValue
@GeneratedValue 用于标注主键的生成策略,通过 strategy 属性指定。默认情况下,JPA 自动选择一个最适合底层数据库的主键生成策略:SqlServer 对应 identity,MySQL 对应 auto increment。
在 javax.persistence.GenerationType 中定义了以下几种可供选择的策略: (1). IDENTITY:采用数据库 ID 自增长的方式来自增主键字段,Oracle 不支持这种方式; (2). AUTO:JPA 自动选择合适的策略,是默认选项; (3). SEQUENCE:通过序列产生主键,通过 @SequenceGenerator 注解指定序列名,MySql 不支持这种方式 (4). TABLE:通过表产生主键,框架借由表模拟序列产生主键,使用该策略可以使应用更易于数据库移植。
5. @Basic
@Basic 表示一个简单的属性到数据库表的字段的映射,对于没有任何标注的 getXxxx() 方法,默认即为@Basic
fetch: 表示该属性的读取策略,有 EAGER 和 LAZY 两种,分别表示主支抓取和延迟加载,默认为 EAGER.
optional:表示该属性是否允许为null, 默认为true
6. @Column
当实体的属性与其映射的数据库表的列不同名时需要使用@Column 标注说明, 该属性通常置于实体的属性声明语句之前,还可与 @Id 标注一起使用。
@Column 标注的常用属性是 name,用于设置映射数据库表的列名。此外,该标注还包含其它多个属性,如:unique 、nullable、length 等。
@Column 标注的 columnDefinition 属性: 表示该字段在数据库中的实际类型.通常 ORM 框架可以根据属性类型自动判断数据库中字段的类型,但是对于Date类型仍无法确定数据库中字段类型究竟是DATE,TIME还是TIMESTAMP.此外,String的默认映射类型为VARCHAR, 如果要将 String 类型映射到特定数据库的 BLOB 或TEXT 字段类型.
@Column标注也可置于属性的getter方法之前
7. @Transient
表示该属性并非一个到数据库表的字段的映射,ORM框架将忽略该属性.
如果一个属性并非数据库表的字段映射,就务必将其标示为@Transient,否则,ORM框架默认其注解为@Basic
8. @Temporal
在核心的 Java API 中并没有定义 Date 类型的精度(temporal precision). 而在数据库中,表示 Date 类型的数据有 DATE, TIME, 和 TIMESTAMP 三种精度(即单纯的日期,时间,或者两者 兼备). 在进行属性映射时可使用@Temporal注解来调整精度.
import java.util.Date;
...
private Date createTime;
//映射到数据库的时间戳类型
@Temporal(TemporalType.TIMESTAMP)
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
private Date birth;
//映射到数据库的日期类型
@Temporal(TemporalType.DATE)
public Date getBirth() {
return birth;
}
9. @TableGenerator
将当前主键的值单独保存到一个数据库的表中,主键的值每次都是从指定的表中查询来获得
这种方法生成主键的策略可以适用于任何数据库,不必担心不同数据库不兼容造成的问题。
//name 属性表示该主键生成策略的名称,它被引用在@GeneratedValue中设置的generator 值中
//table 属性表示表生成策略所持久化的表名
//pkColumnName 属性的值表示在持久化表中,该主键生成策略所对应键值的名称
//valueColumnName 属性的值表示在持久化表中,该主键当前所生成的值,它的值将会随着每次创建累加
//pkColumnValue 属性的值表示在持久化表中,该生成策略所对应的主键
//allocationSize 表示每次主键值增加的大小, 默认值为 50
@TableGenerator(name="ID_GENERATOR",table="JPA_ID_GENERATES",pkColumnName="PK_NAME",pkColumnValue="CUSTOMER_ID",valueColumnName="PK_VALUE",allocationSize=100)
@GeneratedValue(strategy=GenerationType.TABLE,generator="ID_GENERATOR")
@Id
public Integer getId() {
return id;
}
JPA项目的开发步骤
(1). 导入 JPA 依赖的 jar 文件
- hibernate-release-x.x.x.Final\lib\required*.jar
- hibernate-release-x.x.x.Final\lib\jpa*.jar
- 数据库驱动的 jar 包
(2). 配置持久化类
Table(name="JPA_CUTOMERS")
@Entity
public class Customer {
private Integer id;
private String lastname;
private String email;
private int age;
private Date createTime;
private Date birth;
@GeneratedValue(strategy=GenerationType.AUTO)
@Id
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@Column(name="last_name",length=50,nullable=false)
public String getLastname() {
return lastname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Date getCreateTime() {
return createTime;
}
@Temporal(TemporalType.TIMESTAMP)
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
@Temporal(TemporalType.DATE)
public Date getBirth() {
return birth;
}
public void setBirth(Date birth) {
this.birth = birth;
}
}
(3). 类路径下的的 META-INF 目录下放置persistence.xml,文件的名称是固定的
<!-- name 属性用于定义持久化单元的名称 transaction-type 指定 JPA 的事务处理策略 (RESOURCE_LOCAL:默认值,数据库级别 的事务,只能针对一种数据库) -->
<persistence-unit name="jpa-1" transaction-type="RESOURCE_LOCAL">
<!--
配置使用什么 ORM 产品来作为 JPA 的实现
1. 实际上配置的是 javax.persistence.spi.PersistenceProvider 接口的实现类
2. 若 JPA 项目中只有一个 JPA 的实现产品, 则也可以不配置该节点.
-->
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>com.axon.jpa.helloworld.Customer</class>
<properties>
<!-- 连接数据库的基本信息 -->
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql:///jpa"/>
<property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.password" value=""/>
<!-- 配置hibernate的基本信息 -->
<!-- 执行操作时是否在控制台打印 SQL -->
<property name="hibernate.show_sql" value="true" />
<!-- 是否对 SQL 进行格式化 -->
<property name="hibernate.format_sql" value="true" />
<!-- 指定自动生成数据表的策略 -->
<property name="hibernate.hbm2ddl.auto" value="update" />
</properties>
</persistence-unit>
(4). 持久化单元操作
// 创建 EntityManagerFactory 对象
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("jpa-1");
// 创建 EntityManager 对象
EntityManager entityManager = entityManagerFactory.createEntityManager();
// 开启事务
EntityTransaction entitytransaction = entityManager.getTransaction();
entitytransaction.begin();
//持久化操作
entityManager.persist(customer);
//提交事务
entitytransaction.commit();
// 关闭 EntityManager
entityManager.close();
//关闭 EntityManagerFactory
entityManagerFactory.close();
Web 服务
EJB
介绍
EJB组件:JavaBean是在编程环境(IDE)中能够被可视化处理的可重用组件,是实现分布式业务逻辑的 Java 组件。我们在开发的时候可以利用这些组件,像搭积木一样建立面向对象的分布式应用。
EJB容器:是EJB组件的运行环境,为部署EJB组件提供服务,包括事务、安全、远程客户端的网络发布、资源管理等。
EJB服务器:管理EJB容器的高端进程或应用程序,并提供对系统服务的访问。调用EJB组件的应该称为EJB客户端,客户端可以运行在Web容器中。
架构
age-20201211150629805.png)]
EJB是什么?
EJB3.0新特性
相比EJB3以前的版本而言,增加了两个新特性:元数据注解(Annotation) 和依赖注入(Injection),而元数据注解以最大限度的使部署描述符从冗余繁杂中脱离出来。
EJB体系结构
EnterpriseBean和Serializable接口一样,是一个标记性接口。用于标记一个类为一个Bean。它有三种实现:SessionBean,EntityBean,MessageDrivenBean。
SessionBean:它是对业务逻辑的封装,类似于我们经常写的Service层。它可以以local, remote, webservice 服务的方式被client调用。
EntityBean:它是对数据库对象的封装,一个EntityBean,就是数据库的一条记录。
MessageDrivenBean:一个messageDrivenBean其实就是一个javax.jms.MessageListener。在JMS中有MessageConsumer,它支持两种接收消息的方式:同步接收采用MessageConsumer#receive()方法,异步接收则是为MessageConsumer设置一个MessageListener,一旦接收到消息,就调用listener#onMessage()。
SessionBean
1、SessionBean服务组件
SessionBean服务端有三大组件Home、EJbObject、SessionBean。
SessionBean是我们编写业务逻辑的地方。譬如数据库操作,进行计算等等。但是它对于客户端是不可见的,一个SessionBean实例的创建、销毁、激活、钝化等都是由EJB容器来管理的。
EJBObject:你可以将EJBObject看作是SessionBean对象的Proxy。需要将你的业务方法同样在EJBObject中复制一份。例如有一个HelloSessionBean#sayHello(str) 业务,如果要将该业务方法暴露出去给Client使用,与之对应的HelloEJBObject中必然得包含#sayHello(str)方法。也就是说Client需要使用EJBObject来达到与SessionBean交互的。
Home:这个名字起的怪异,我们可以将其理解为一个SessionBean的Factory。EJB容器通过Home对象来创建SessionBean对象,并装配出它的代理对象(EJBObject对象)。这是它的唯一用途。
2、Remote与Local
对于Home,和EJBObject,它们俩个都分为两类:Remote,Local。
Remote模式的,主要用于不在同一个JVM进程里,而在同一个进程里使用时,只需要使用Local模式的即可,这样选择自然是为了性能考虑。
3、Client访问处理流程(很容易看出Local性能好在哪里)
3.1 Remote模式下SessionBean 的访问流程
1、客户端通过JNDI获取到Home对象(EJBHome)的引用2、客户端使用homeRef#create()方法来创建出EJBObject的Stub。 2.1)客户端底层使用Socket通信将次过程发给服务端Skeleton。 2.2)Skeleton调用服务端的Home对象的create方法,分配SessionBean对象(可能是新创建一个,也可能是从对象池中取一个,具体怎样依赖于是否是Stateful的),同时为该SessionBean对象生成一个代理对象(EJBObject实例),然后返回代理对象的引用。 2.3)客户端拿到EJBObject的引用就是Stub对象。 3、客户端访问业务 3.1) 客户端底层使用Socket通信将次过程发给服务端Skeleton。 3.2)Skeleton根据请求找到该EJBObject,调用与之关联的SessionBean的相应的业务。返回结果 3.3)客户端得到调用结果
3.2 Local模型下SessionBean的访问流程
1、客户端通过JNDI获取到Home对象(EJBLocalHome)的引用2、客户端使用homeRef#create()方法来创建出EJBLocalObject(怎么创建也要依赖于是否的Stateful的) 3、客户端访问业务
常用注解
**@Stateless:**标记类把Java类声明为一个无状态会话bean
**@EJB:**表示注入实例,EJB注入和Resource注入相比,EJB注入只是针对于EJB而言,而Resource注入即是对所有的文件都可以进行注入。
**@Remove:**为会话 Bean 声明远程业务接口。用在接口上时,将该接口指定为远程业务接口。在这种情况下,不提供任何 value()。用在方法上,通过这个注解来说明在调用这个方法之后bean的实例将被清除掉。
**@Local:**用在 Bean 类上时,为会话 Bean 声明本地业务接口。用在接口上时,将该接口指定为本地业务接口。在这种情况下,不提供任何 value()。如:@Local(LawsuitService.class)
**@Stateful:**有状态会话 Bean 的组件定义注释。
**@Timeout:**指定无状态会话 Bean 类或消息驱动 Bean 类上接收该 Bean 的 EJB 计时器过期的方法。
**@TransactionAttribute:**在 TYPE-level 应用时,为会话或消息驱动 Bean 的所有业务方法指定默认事务属性。在方法级应用时,仅为该方法指定事务属性。
如:@TransactionAttribute(TransactionAttributeType.SUPPORTS)、
@TransactionAttribute(TransactionAttributeType.REQUIRED)。
**@Interceptors:**声明类或方法的拦截器的有序列表。
**@Lock:**方法声明一个并发锁的单例bean具有容器管理的并发。
**@Schedule(排程器):**计划时间为自动建立一个超时计划基于一个时间表达式。
**@Startup:**标记一个单例在应用初始化期间。
**@ConcurrencyManagement:**声明单例或有状态bean的并发管理类型
JavaEE 框架技术
配置文件
web.xml 的配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<display-name>Sample Application</display-name>
<description>This is a sample application</description>
<!-- 在此设定的参数,可以在servlet中用 getServletContext().getInitParameter("my_param") 来取得 -->
<context-param> <!-- 用来设定web站台的环境参数 -->
<param-name>my_param</param-name>
<param-value>hello</param-value>
</context-param>
<filter>
<!-- 过滤器名,可以随便取,当web应用中有多个过滤器时不允许重名. -->
<filter-name>SampleFilter</filter-name>
<!-- 具体的过滤器的类的完整的包名+类名。注意:不能写错了。否则容器不能正确的实例化过滤器 -->
<filter-class>mypack.SampleFilter</filter-class>
<init-param>
<!-- 参数名 -->
<param-name>initParam1</param-name>
<!-- 参数值 -->
<param-value>2</param-value>
</init-param>
</filter>
<!-- Define the SampleFilter Mapping -->
<filter-mapping>
<!-- 过滤器名,注意要和上面的<filter-name>里的名字一样。-->
<filter-name>SampleFilter</filter-name>
<!--
指定过滤器负责过滤的URL。这里指定了*.jsp表示在访问任何一个jsp页面时都会先使用mypack.SampleFilter过滤器进行过滤。
如果写成login.jsp.则只有在访问login.jsp时才会调用该过滤器进行过滤。-->
<url-pattern>*.jsp</url-pattern>
</filter-mapping>
<servlet>
<!-- Servlet名字,可以随便取,有多个Servlet时不允许重名 -->
<servlet-name>SampleServlet</servlet-name>
<!-- 指定实现这个Servlet的类。完整的包名+类名 -->
<servlet-class>mypack.SampleServlet</servlet-class>
<!-- 定义Servlet的初始化参数(包括参数名和参数值)
一个<servlet>元素里可以有多个<init-param>元素。
在Servlet类中通过ServletConfig类的来访问这些参数。-->
<init-param>
<!-- 参数名 -->
<param-name>initParam1</param-name>
<!-- 参数值 -->
<param-value>2</param-value>
</init-param>
<!-- 指定当前Web应用启动时装载Servlet的次序。当这个数>=0时,容器会按数值从小到大依次加载。如果数值<0或没有指定,容器将载Web客户首次访问这个Servlet时加载。-->
<load-on-startup>1</load-on-startup>
</servlet>
<!-- Define the SampleServlet Mapping -->
<servlet-mapping>
<!-- 必须和<servlet>里的<servlet-name>内容一样 -->
<servlet-name>SampleServlet</servlet-name>
<!--指定访问这个Servlet的URL。这里给出的是对于整个Web应用的相对URL路径。-->
<url-pattern>/sample</url-pattern>
</servlet-mapping>
<session-config>
<!--设定HttpSession的生命周期。这里以分钟计算。下面的设定指明Session在最长不活动时间为10分钟。
过了这个时间,Servlet容器将它作为无效处理。
注意这里和程序里指定的计数单位不同,程序里是以秒为单位。
<session-config>只有<session-timeout>这个元素 -->
<session-timeout>10</session-timeout>
</session-config>
<!-- 配置会话侦听器,class表示一个
HttpSessionListener 或 HttpSessionActivationListener
或 HttpSessionAttributeListener 或 HttpSessionBindingListener的实现类。
该节点允许多个 -->
<listener>
<listener-class>com.cn.SessionListenerImpl</listener-class>
</listener>
<!--在 用户访问Web应用时,如果仅给出Web应用的根访问URL,没有指定具体的文件名,容器会调用
<weblcome-file- list>元素里指定的文件清单。
<welcome-file-list>里允许有多个<welcome-file>元素,每个元素代表一个文件。
容器会先找第一文文件件是否存在,如果存在这把这个文件返回个客户,不再进行其他文件的查找。如果不存在则找第二个文件,依次 类推。
如果所有文件都不存在,则跑出404错误 -->
<welcome-file-list>
<welcome-file>login.jsp</welcome-file>
<welcome-file>index.htm</welcome-file>
</welcome-file-list>
<!-- 设置Web应用引用的自定义标签库。下面的代码定义了一个/mytaglib标签库,它对应的TLD文件为/WEB-INF/mytaglib.tld -->
<taglib>
<taglib-uri>/mytaglib</taglib-uri>
<taglib-location>/WEB-INF/mytaglib.tld</taglib-location>
</taglib>
<!-- 如果Web应用访问了由Servlet容器管理的某个JNDI Resource必须在这里声明对JNDI Resource的引用 -->
<resource-ref>
<!-- 对应用资源的说明 -->
<description>DB Connection</description>
<!-- 指定所引用资源的JNDI名字 -->
<res-ref-name>jdbc/sampleDb</res-ref-name>
<!-- 指定所引用资源的类名字 -->
<res-type>javax.sql.DataSource</res-type>
<!-- 指定管理所引用资源的Manager,
它有两个可选值:Container和Application.Container表示由容器来创建和管理Resource,Application表示由Web应用来管理和创建Resource -->
<res-auth>Container</res-auth>
</resource-ref>
<security-constraint>
<web-resource-collection>
<!-- 这个名字是必须的,由工具使用,别的地方不使用 -->
<web-resource-name>my application</web-resource-name>
<!-- 指定要受约束的资源,至少有一个。可以有多个. -->
<uri-pattern>/*</uri-pattern>
<!-- 描 述了度可与URL模式指定的资源哪些方法是受约束的,如果没有<http-method>元素,表示任何角色的人都无法访问任何http的方 法
。这里放置了GET方法,表示只有GET方法是受约束的。其他任何角色的人可以访问POST和其他的方法。但不能访问GET方法。-->
<http-method>GET</http-method>
</web-resource-collection>
<!-- 如果没有<auth-constraint>表示所有角色都能访问GET方法,如果是<auth-constraint/>表示任何角色都不能访问GET方法 -->
<auth-constraint>
<!-- 可选的。表示哪些角色能够在指定的资源上调用受约束的方法。这里表示只有拥有Admin和Member角色的人能够访问GET方法
<security-role>>里的<role-name>值一样 -->
<role-name>Admin</role-name>
<role-name>Member</role-name>
</auth-constraint>
</security-constraint>
<!-- 将指定的角色映射到web.xml里 -->
<security-role>
<description>The role that is required to log into the my Application
</description>
<!-- 以下的角色和tomcat-users.xml里的<tomcat-users>里的<role rolename=""/>里的rolename属性值对应 -->
<role-name>Guest</role-name>
<role-name>Admin</role-name>
<role-name>Member</role-name>
</security-role>
<!-- 如果要想进行认证,必须有<login-config>-->
<login-config>
<!--认证方式。有4种:BASIC:基本。 DIGEST:摘要。CLIENT-CERT:客户证书(能提供最高强度的认证)。FORM:表单 -->
<auth-method>FORM</auth-method>
<realm-name>
Tomcat Servet Configuraton Form-Based Authentication Area
</realm-name>
<form-login-config>
<form-login-page>/login.jsp</form-login-page>
<form-error-page>/error.jsp</form-error-page>
</form-login-config>
</login-config>
<error-page> <!-- 用来处理错误代码或异常的页面,有三个子元素: -->
<error-code>404</error-code> <!-- 指定错误代码 -->
<exception-type>java.lang.Exception</exception-type> <!-- 指定一个JAVA异常类型 -->
<location>/error404.jsp</location> <!-- 指定在web站台内的相关资源路径 -->
</error-page>
<mime-mapping> <!-- 定义某一个扩展名和某一个MIME Type做对映,包含两个节点 -->
<extension>doc</extension> <!-- 扩展名的名称 -->
<mime-type>application/vnd.ms-word</mime-type> <!-- MIME格式 -->
</mime-mapping>
<mime-mapping>
<extension>xls</extension>
<mime-type>application/vnd.ms-excel</mime-type>
</mime-mapping>
</web-app>
java部分的代码
// 格式化日期
Date dt = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmSSsss");
String res = sdf.format(dt);
// 设置字符编码
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
// 获得当前得时间
LocalDate dt=LocalDate.now();
Date dt1=Date.valueOf(dt);
// 操作数据库
String sql="select username from manager where username=? and userpwd=?";
conn=this.getConnection();
PreparedStatement psmt=conn.prepareStatement(sql);
// 替代上面问号的位置
psmt.setString(1, username);
psmt.setString(2, userpwd);
ResultSet rs=psmt.executeQuery();
上传文件的代码
protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
HttpSession session = request.getSession();
if (session.isNew()) {
response.sendRedirect("login.jsp");
return;
}
Object oUsername = session.getAttribute("username");
if (oUsername == null) {
response.sendRedirect("login.jsp");
return;
}
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
String username = (String) oUsername;
Part part = request.getPart("myfile");
String clientFileName = part.getSubmittedFileName();
if (clientFileName=="") {
session.setAttribute("message", "您没有选择文件!");
response.sendRedirect("show_operation_msg.jsp");
return;
}
String webAppPath = this.getServletContext().getRealPath("/");
String serverFilePath = webAppPath + this.getServletContext().getInitParameter("uploadFilePath");
String serverFileNameWithPath = serverFilePath + "\\"
+ UploadServlet.produceServerFileNameByUserAndTime(username, clientFileName);
part.write(serverFileNameWithPath);
String message="文件:"+clientFileName+"上传成功!<br>"
+"文件保存到:"+serverFileNameWithPath;
session.setAttribute("message", message);
session.setAttribute("back_url", "uploadfile.jsp");
response.sendRedirect("show_operation_msg.jsp");
}
拦截器
/**
* 对任意客户端请求进行过滤,若用户请求url中不包含manage字符串,则将把请求转给对应资源
* 反之,就检验session中是否存在 username属性,不存在转向index.jsp页面,存在则将请求转给对应资源
*/
@WebFilter(filterName ="checkloginFilter",urlPatterns = {"/*"})
public class CheckLoginFilter extends HttpFilter {
@Override
public void doFilter(HttpServletRequest request
, HttpServletResponse response
, FilterChain filterChain) throws IOException,ServletException {
String url=request.getRequestURL().toString();
boolean isRedirectIndexPage=false;//是否转向index.jsp
if(url.contains("manage")&&request.getSession().getAttribute("username")==null){
isRedirectIndexPage=true;
}
if(isRedirectIndexPage){
request.getRequestDispatcher("index.jsp").forward(request,response);
}else {
filterChain.doFilter(request,response);
}
}
}
MVC 的设计流程
- 定义JavaBeans存储数据
- 编写servlet处理请求
- 数据结果存储在作用域中
- 转发请求到JSP页面
- 从JavaBeans中提取数据