返回首页

JavaEE

JavaEE 学习笔记

Lecture 1#

结构#

Lecture 2#

Spring#

  • 一个复杂而又简洁的 javabean 工厂,管理 bean 的创建和依赖
  • 很普通又很实用的框架,提取了大量实际开发中通用的设计思想和模式,抽象而成的一个框架
  • 轻量级的、非侵入式(不依赖 Spring API )的应用框架
  • 集成已存在的成熟应用解决方案,开发简单高效

优点:

  1. 低侵入式设计
  2. 独立于各种应用服务器
  3. Spring 的 DI 容器,提高组件之间的解耦
  4. SpringAOP 提供通用任务的集中统一处理(安全、事务、日志等),实现更好的代码复用
  5. Spring 的 ORM 和 DAO 提供了与第三方持久层框架的良好整合
  6. 高度开放,可以自由选用 Spring 框架的部分或全部
Bean 容器画像#

<bean id="group" class="zust.se.Group">
    <property name="id" value="100"/>
    <property name="name" value="GroupA/>
</bean>
BeanFactory ac=new BeanFactory("bean.xml");
Group group=(Group) ac.getBean("group");
System.out.printIn(JSON.toJSONString(group));
IOC 和 DI#

由容器来管理对象之间的依赖关系,“控制反转”或“依赖注入”

IOC(Inversion of Control):由容器来负责控制对象的生命周期和对象间的关系 DI(Dependency Injection):在系统运行中,由容器动态的向某个对象提供它所需要的其他对象

DI 注入的两种方式:

  • 设值注入 ​IOC 容器使用属性的 setter 方法来注入被依赖的实例
<property name="userDao" ref="userDao"/>
  • 构造注入 IOC 容器使用构造器来注入被依赖的实例,按构造函数参数顺序指定对应要注入值,— 用 index 属性指定顺序,从 0 开始
<constructor-arg ref="db"/>

Lecture 3#

IOC#

Spring 通过 IoC 容器来管理对象的实例化和初始化,以及对象从创建到销毁的整个生命周期

创建 bean 实例#

  • BeanFactory 容器 BeanFactory 是一个管理 Bean 的工厂,它主要负责初始化各种 Bean,并调用它们的生命周期方法
Resource resource = new ClassPathResource("applicationContext.xml");
BeanFactory factory = new XmlBeanFactory(resource);
  • ApplicationContext 容器 ApplicationContext 继承了 BeanFactory 接口,是 BeanFactory 的拓展,增加了例如 AOP、国际化、事件支持等功能
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(String configLocation);
  • Web 服务器实例化 ApplicationContext 容器通常使用基于 ContextLoaderListener 实现
<context-param>
  <param-name>contextConfigLocation</param-name>
  <!--加载spring目录下的applicationContext.xml文件-->
  <param-value>
      classpath:spring/applicationContext.xml
  </param-value>
</context-param>
<!--指定以ContextLoaderListener方式启动Spring容器-->
<listener>
  <listener-class>
      org.springframework.web.context.ContextLoaderListener
  </listener-class>
</listener>

注入#

  • 注入普通属性

  • 注入 bean 引用

  • bean 的自动装配

  • 注入嵌套 bean:不被 spring 访问,将嵌套的 bean 注入 property 属性中

  • 注入集合类型值:

bean 的作用域 scope#

  1. singleton(默认): 单例模式,在整个容器中只有一个实例【可跟踪进行生命周期管理】

  2. prototype:原型模式 ,每次通过 getBean 获取时产生一个新的实例

  3. request:每次 http 请求产生一个新的实例,web 应用。须在 web.xml 中配置相应的 Listener 或 filter

  4. Session:每次 http session 产生一个新的实例 ,web 应用

bean 的生命周期#

  • 注入之后——init-method
<bean id="chinese" class="org.j2ee.service.impl.Chinese"
init-method="init">
<property name="axe" ref="steelAxe"/>
</bean>
  • 销毁之前——destroy-method
<bean id="chinese" class="org.j2ee.service.impl.Chinese"
destroy-method="destroy">
<property name="axe" ref="steelAxe"/>
</bean>

Spring 国际化#

使用 MessageSource 接口

注解装配 Bean#

  1. @Component:注解描述 Spring 中的 Bean,但它是一个泛化的概念,仅仅表示一个组件(Bean),并且可以作用在任何层次
  2. @Repository:用于将数据访问层(DAO 层)的类标识为 Spring 中的 Bean,其功能与 @Component 相同
  3. @Service:通常作用在业务层(Service 层),用于将业务层的类标识为 Spring 中的 Bean,其功能与 @Component 相同
  4. @Controller:通常作用在控制层(Controller),用于将控制层的类标识为 Spring 中的 Bean,其功能与 @Component 相同
  5. @Autowired:可以应用到 Bean 的属性变量、属性的 setter 方法、非 setter 方法及构造函数等,配合对应的注解处理器完成 Bean 的自动配置工作。默认按照 Bean 的类型进行装配
  6. @Resource:与 Autowired 相同,区别在于 @Autowired 按照 Bean 类型装配,而 @Resource 按照 Bean 实例名称进行装配
<!--使用context命名空间,通知spring扫描指定目录,进行注解的解析 -->
    <context:component-scan
        base-package="net.biancheng" />
@Value("${u.id}") // 通过@Value将配置文件中u.id的值注入给user的id属性
<contect:component-scan base-package="se.zust" />

生命周期(在类的成员方法定义语句前注解)

  • @PostConstruct:注解的方法将会在对象完成构造且依赖注入完成后被自动调用
  • @PreDestroy:注解的方法将在 bean 对象销毁之前被自动调用

Java 日志配置(log4j)#

resources 新建 log4j.properties pom.xml 添加依赖 为类添加 logger 静态属性

用 logger 输出日志:logger.debug、logger.info、logger.warn、logger.error、logger.fetal

Spring 测试#

  • JUnit:Java 语言的单元测试框架 ​ 在任意方法前加@Test 注解

  • 容器测试

    1. 测试类前添加注解@RunWith 和@ContextConfiguration
    2. 通过@Resource 给测试类注入容器中的 bean

Lecture 4#

AOP#

  • 横向抽取机制(动态代理),取代了传统纵向继承机制的重复性代码
  • 可以通过预编译方式和运行期间动态代理实现在不修改源代码的情况下给程序动态统一添加功能
  • 主要作用是分离功能性需求和非功能性需求,使开发人员可以集中处理某一个关注点或者横切逻辑,减少对业务代码的侵入,增强代码的可读性和可维护性
  • 适用于:日志管理、事务处理、权限控制、异常处理…

概念:

名称说明
Joinpoint(连接点)指可以被动态代理拦截目标类的方法,表示“在什么地方做”
Pointcut(切入点)指要对哪些 Joinpoint 进行拦截,即被拦截的连接点
Advice(通知)/增强处理对切入点增强的内容,表示“具体怎么做”,before、after…
Target(目标)指代理的目标对象
Weaving(织入)指把增强代码应用到目标上,生成代理对象的过程
Proxy(代理)指生成的代理对象
Aspect(切面)一个关注点的模块化,横切多个对象,切入点和通知的结合
关注点要做什么,公共功能,如:事务管理
通知说明
before(前置通知)通知方法在目标方法调用之前执行
after(后置通知)通知方法在目标方法返回或异常后调用
after-returning(返回后通知)通知方法会在目标方法返回后调用
after-throwing(抛出异常通知)通知方法会在目标方法抛出异常后调用
around(环绕通知)通知方法会将目标方法封装起来
基于 xml 开发 aop#
  1. 在 xml 中导入 Spring aop 命名空间
  2. 定义切面(将 bean 转化为切面)
<aop:config>
    <aop:aspect id="myAspect" ref="aBean">
        ...
    </aop:aspect>
</aop:config>

其中,id 用来定义该切面的唯一表示名称,ref 用于引用普通的 Spring Bean

  1. 定义切入点
<aop:config>
    <aop:pointcut id="myPointCut"
        expression="execution(* net.biancheng.service.*.*(..))"/>
</aop:config>

id 用于指定切入点的唯一标识名称,execution 用于指定切入点关联的切入点表达式

  1. 定义通知

AspectJ 支持 5 种类型的 advice

<aop:aspect id="myAspect" ref="aBean">
    <!-- 前置通知 -->
    <aop:before pointcut-ref="myPointCut" method="..."/>
    <!-- 后置通知 -->
    <aop:after-returning pointcut-ref="myPointCut" method="..."/>
    <!-- 环绕通知 -->
    <aop:around pointcut-ref="myPointCut" method="..."/>
    <!-- 异常通知 -->
    <aop:after-throwing pointcut-ref="myPointCut" method="..."/>
    <!-- 最终通知 -->
    <aop:after pointcut-ref="myPointCut" method="..."/>
    ....
</aop:aspect>
基于注解开发 aop#
名称说明
@Aspect用于定义一个切面
@Pointcut用于定义一个切入点
@Before用于定义前置通知,相当于 BeforeAdvice
@AfterReturning用于定义后置通知,相当于 AfterReturningAdvice
@Around用于定义环绕通知,相当于 MethodInterceptor
@AfterThrowing用于定义抛出通知,相当于 ThrowAdvice
@After用于定义最终 final 通知,不管是否异常,该通知都会执行
  1. 在 XML 文件中添加以下内容启动@AspectJ
<aop:aspectj-autoproxy>
  1. 定义切面
@Aspect
public class AspectModule {
}
  1. 定义切入点
// 要求:方法必须是private,返回值类型为void,名称自定义,没有参数
@Pointcut("execution(*net.biancheng..*.*(..))")
private void myPointCut() {
}
  1. 定义通知
@Before("myPointCut()")
public void beforeAdvice(){
    ...
}

Lecture 5#

ORM#

ORM 是 Object Relational Mapping 的缩写,“对象关系映射”,它解决了对象和关系型数据库之间的数据交互问题

数据库类/对象
表(table)类(class)
表中的记录(record,也称行)对象(object)
表中的字段(field,也称列)对象中的属性(attribute)

ORM 通过使用描述对象和数据库之间映射的,将 java 程序中的对象自动持久化到关系数据库中

在业务逻辑层和呈现层中,我们是面向对象的。当对象信息发生变化的时候,我们需要把对象的信息保存在关系数据库中

(避免数据访问层代码重复)

JPA#

Java Persistence API,就是 java 持久化 api,是基于 ORM 的一种规范

开发步骤:

  • 创建 maven 项目
  • 加入 hibernate-entitymanager 依赖包
  • 加入数据库 mysql-connector-java 依赖包
  • 在 resources/META-INF 中添加 persistence.xml 配置 JPA,配好实体类的包扫描,— 在实体类包中为每张表对应

  • 建立一个实体类 JavaBean
  • 创建 javabean
  • 为数据库字段添加对应属性
  • 在类前面添加@Entity 和@Table(“”)注解属性
  • 在属性前添加相应注解

  1. 表注解:在实体类定义语句前注解
@Entity
​@Table(name="tableName")
  1. 主键:在主键对应属性的 getter 方法前注解
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name = "keyName")
  1. 普通属性:在对应属性的 getter 方法前注解
​@Column(name = "propName")
@Basic(fetch=FetchType.LAZY|EAGER)
// LAZY:懒加载
// EAGER:立即加载,默认值

JPA 操作数据库:

  • 利用 jpa 配置创建 entityManager
  • 利用 entityManager 的接口方法操作数据库
单元描述
EntityManagerFactoryEntityManager 的工厂类,它创建并管理多个 EntityManager 实例
EntityManager这是一个接口,它管理的持久化操作的对象
Entity实体,是持久性对象,是存储在数据库中的记录
EntityTransaction与 EntityManager 一对一关系;对于每一个 EntityManager,由 EntityTransaction 类维护
Persistence这个类包含静态方法来获取 EntityManagerFactory 实例
Query该接口由每个 JPA 供应商,能够获得符合标准的关系对象
/**
 * 通过Persistence获取EntityManagerFactory,
 * 传入参数对应配置文件中持久化单元persistence-unit的name
 * 通过EntityManagerFactory创建EntityManager
 * 获取EntityTransaction
 * 开启事务
 */
EntityManagerFactory entityManagerFactory;
EntityManager entityManager;
entityManagerFactory =
        Persistence.createEntityManagerFactory("jpa");
entityManager = entityManagerFactory.createEntityManager();
entityManager.getTransaction().begin();
//数据操作代码
/**
 * 提交事务
 * 关闭entityManager
 * 关闭entityManagerFactory
 */
entityManager.getTransaction().commit();
entityManager.close();
entityManagerFactory.close();

持久化对象状态:

  • 瞬时对象(New Objects):使用 new 操作符初始化的对象不是立刻就持久的。它们的状态是瞬时的,也就是说它们没有任何跟数据库表相关联的行为,只要应用不再引用这些对象,它们的状态将会丢失,并由垃圾回收机制回收。
  • 托管对象(Manage Objects):持久实例是任何具有数据库标识的实例。它有持久化管理器 EntityManager 统一管理,持久实例是在事务中进行操作的——它们的状态在事务结束时同数据库进行同步。当事务提交时,通过执行 SQL 的 INSERT、UPDATE 和 DELETE 语句把内存中的状态同步到数据库中。
  • 离线对象(Detached Objects):EntityManager 关闭之后,持久化对象就变为离线对象。离线表示这个对象不能再与数据库保持同步,它们不再受 JPA 管理。

持久化对象生命周期:

Lecture 6#

Lombok#

@Data 注解生成实体类属性的 getter/setter 等方法

用@Setter、@Getter 代替@Data

@Data 注解不仅帮我们实现了生成了 getter/setter 同时还重写了 equals(Object other) 和 hashCode()方法, Lombok 会将 Project 类中的 List projects 当做是 hashCode 计算的一部分(同理,equals,toString 也会存在同样的问题),而如果我的项目中出现循环引用,这就会导致死循环,最终就会抛出 StackOverFlowError

单表映射#

双向一对一关系

@OneToOne(optional = true, cascade = CascadeType.ALL)
@JoinColumn(name="id_card_id")
private TidCard tidCard;
@OneToOne(cascade = CascadeType.ALL, mappedBy = "tidCard")
private Tuser tuser;

多表映射#

双向一对多关系

@OneToMany(cascade = CascadeType.ALL,fetch =FetchType.LAZY,mappedBy = "tuser")
private Set<TcreditCard> tcreditCards;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="user_id",insertable = false,updatable = false)
private Tuser tuser;

级联 cascade#

两个对象之间的操作联动关系,对一个对象执行了操作之后,对其指定的级联对象也需要执行相同的操作

CascadeType. PERSIST 级联持久化 ( 保存 ) 操作 CascadeType. MERGE 级联更新 ( 合并 ) 操作 CascadeType. REFRESH 级联刷新操作,只会查询获取操作 CascadeType. REMOVE 级联删除操作 CascadeType. ALL 级联以上全部操作

Lecture 7#

hql#

Query query = entityManager.createQuery(
    "from User user where user.name like 'J%'");
List<User> users = query. getResultList();

hql 步骤:

  1. 获取 JPA 的 entityManager 对象
  2. 编写 HQL 语句
  3. entityManager.createQuery(HQL)创建 Query 对象
  4. query.setXXX 设置查询参数
  5. query. getResultList()得到查询结果(持久化实体集)

Lecture 8#

步骤:

  • 创建 maven 项目
  • 添加 MyBatis 依赖
  • 在 resources 下创建 jdbc.properties(可以是其他名字)
  • 在 resources 下创建 SqlMapper.xml(可以是其他名字)
  • 在 entity 包中创建 POJO(不一定与表对应)
  • 在 dao 包中创建 mapper 接口
  • 在 mapper 包中创建 mapper 配置文件,文件中每个 select 的 id 与 mapper 接口中的一个方法对应
  • 编写测试类进行测试

MyBatis 接口方法:

配置:

测试:

#{} 占位符 、${} 拼接符:

  • #{} 为参数占位符 ?,即 sql 预编译,能防止 sql 注入,有‘ ’单引号,建议多使用
  • ${} 为字符串替换,即 sql 拼接,不能防止 sql 注入,无单引号;表名,orderby 必须用

JPA、MyBatis 对比#

Hibernate:

目前最流行的 ORM 框架,设计灵巧,文档丰富(完全自动操作),只是性能不好控制(自己去控制性能,不是很好控制)。Hibernate 是一个完整的 ORM 框架,常规 CRUD 我们不需要写一句 SQL;各大 ORM 框架实现这个规范。可以自动建表。

MyBatis:

允许开发人员直接编写 SQL(更好灵活)。并不是一个完整的 ORM 框架,因为我们还需要自己去写全部 SQL。不是完整的 ORM,程序员需要自己去写全部的 SQL,可以进行更为细致的 SQL 优化,轻量级框架,学习成本低,性能好控制。不能自动建表。 SQL 映射框架,将 SQL 结果与对象进行映射 半自动:开发人员写 SQL,通过 iBatis 映射成对象

两者对比:MyBatis 是一个小巧、方便、高效、简单、直接、半自动化的持久层框架,JPA是一个强大、方便、高效、复杂、间接、全自动化的持久层框架规范

Lecture 8-2#

Spring Data#

Spring 的一个子项目。用于简化数据库访问,支持 NoSQL 和关系数据存储。其主要目标是使数据库的访问变得方便快捷

JpaRepository#
  • List findAll(); //查找所有实体
  • List findAll(Sort sort); //排序、查找所有实体
  • List save(Iterable<? extends T> entities); //保存集合
  • void flush(); //执行缓存与数据库同步
  • T saveAndFlush(T entity); //强制执行持久化
  • void deleteInBatch(Iterable entities); //删除一个实体集合

Lecture 9#

Web MVC 演进#

  1. jsp+bean
  2. 标准 MVC
  3. Web MVC(请求-响应,前后端分离)

MVC#

一种基于 Java 的实现了 Web MVC设计模式的请求驱动类型的轻量级Web框架,即使用了MVC架构模式的思想,将Web层进行职责解耦 基于请求驱动指的就是使用请求-响应模型。Spring Web MVC简化日常Web` 开发,支持本地化(Locale)解析、主题(Theme)解析及文件上传等;提供了非常灵活的数据验证、格式化和数据绑定机制;提供了强大的约定大于配置(惯例优先原则)的契约式编程支持

  • 前端控制器:DispatcherServlet
  • 应用控制器:映射管理器(Handler Mapping)+视图解析器(View Resolver)
  • 页面控制器:Controller (可以实现 Controller 接口,也可以是 POJO)

开发步骤:

  1. 新建 maven 项目,补全项目结构
  2. 添加 SpringMVC 包依赖及 jetty 配置
  3. 修改 web.xml,添加 springmvc 控制器配置
  4. 在 WEB-INF 下添加 SpringMVC 的配置文件(包扫描及 resolver 配置)

规划用户请求:

  1. 开发 controller
  2. 开发视图(jsp)
  3. clean jetty:run -Djetty.port=8088 编译启动 web 站点
  4. 测试站点

Lecture 10#

Spring MVC#

web.xml: Spring MVC 是基于 Servlet 的,DispatcherServlet 是整个 Spring MVC 框架的核心,主要负责截获请求并将其分派给相应的处理器处理。所以配置 Spring MVC,首先要定义 DispatcherServlet

  • 部署 DispatcherServlet
  • 表示容器再启动时立即加载 servlet
  • 处理所有 URL

controller:

请求方法说明
GET多次执行同一 GET 请求,不会对系统造成影响,具有幂等性[指多个相同请求返回相同的结果],充分使用客户端的缓存
POSTPOST 方法,通常表示“创建一个新资源”,但它既不安全也不具有幂等性(多次操作会产生多个新资源)

参数类型绑定:

  • @RequestParam 绑定请求参数
  • @RequestHeader 绑定请求头参数
  • @CookieValue 绑定 Cookie 的值
  • @PathVariable 绑定 URL 中的变量
@RequestMapping(value="/handle1")
public String handle1(@RequestParam("userName") String userName,
    @RequestParam("password") String password,
    @RequestParam("realName") String realName){
    ...
}

命令/表单对象绑定:

@RequestMapping(value = "/handle14")
public String handle14(User user) {
…
}

Servlet API 对象作为入参: 如果处理方法自行使用 HttpServletResponse 返回响应,则处理方法的返回值设置成 void 即可

@RequestMapping(value = "/handle21")
public void handle21(HttpServletRequest request,HttpServletResponse response) {
    String userName = WebUtils.findParameterValue(request, "userName");
    response.addCookie(new Cookie("userName", userName));
}

or

@Autowired
HttpServletRequest request;
@Autowired
HttpServletResponse response;
@RequestMapping(value = "/handle21")
public void handle21()

视图解析:

jstl

<!-- 视图解析器 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
          id="viewResolver"
          p:prefix="/WEB-INF/jsp/" p:suffix=".jsp">
    </bean>
  1. 发起请求到前端控制器(DispatcherServlet)
  2. 前端控制器请求 HandlerMapping 查找 Handler 可以根据 xml 配置、注解进行查找
  3. 处理器映射器 HandlerMapping 向前端控制器返回 Handler
  4. 前端控制器调用处理器适配器去执行 Handler
  5. 处理器适配器去执行 Handler
  6. Handler 执行完成给适配器返回 ModelAndView
  7. 处理器适配器向前端控制器返回 ModelAndView ModelAndView 是 springmvc 框架的一个底层对象,包括 Model 和 view
  8. 前端控制器请求视图解析器去进行视图解析,根据逻辑视图名解析成真正的视图(jsp)
  9. 视图解析器向前端控制器返回 View
  10. 前端控制器进行视图渲染。视图渲染将模型数据(在 ModelAndView 对象中)填充到 request 域
  11. 前端控制器向用户响应结果

JSON:

  • 输出 json——@ResponseBody
  • 输入 json——@RequestBody

// 让Spring MVC不处理静态资源
<mvc:default-servlet-handler />
<mvc:annotation-driven />

Lecture 11#

SSH#

分层:

  • Web 层(controller):处理用户请求并予以响应,需要业务层 bean 提供业务支持
  • 业务层:为 Web 层的 controller 方法提供业务方法支持,需要数据层 bean 提供数据支持
  • 数据库:为业务层 bean 的方法提供数据支持,需要提供 sessionFactory 来管理和使用映射对象

整合基本思路:

  • SpringMVC 与 Spring 天然整合
  • JPA/Hibernate 整合到 Spring
    1. 关键是 entityManagerFactory
    2. 将 datasource 和 entityManagerFactory 作为 bean 配置到 Spring 中
    3. 在 Dao 中注入 entityManagerFactory
    4. 当 Dao 通过@Repository 加入 Spring 容器

SSH 的 javaweb 项目中的容器:

  • Spring 的容器:由 listener 启动,为父容器
  • SpringMVC 容器:由 dispatchservlet 启动,为子容器
  • SpringMVC 里在配置 controller 时,可以直接引用在 spring 中配置的 service 类;
  • 在 web.xml 配置中,要先配置 spring 的配置,然后配置 spring mvc 的配置,否则 spring mvc 的子容器无法使用父容器中的资源
  • 父容器中的 bean 不能引用子容器中的 bean

整合启动配置:

整合步骤:

  • 在 web 中启动 Spring 容器
  • 配置监听器
  • 将所有业务 bean 通过注解部署到容器中
  1. 包扫描
  • Controller 用@Controller 注解 ​- Service 用@Service 和@Transactional 注解
  • ​Dao 用@Repository 注解
  1. Bean 配置(datasource、 entityManagerFactory )

SSH 架构项目分析设计