Spring简析

MVC

虽然MVC并不是Java当中独有的,但是现在几乎所有的B/S(Browser/Server,浏览器/服务器模式)的架构都采用了MVC框架模式.

控制器Controller:控制器即是控制请求的处理逻辑,对请求进行处理,负责请求转发;

视图View:视图即是用户看到并与之交互的界面,比如HTML,JSP,FreeMarker模板等.

模型Model:模型代表着一种企业规范,就是业务流程/状态的处理以及业务规则的规定.业务流程的处理过程对其它层来说是不透明的,模型接收视图数据的请求,并返回最终的处理结果.业务模型的设计可以说是MVC的核心.

Spring框架

spring 是众多开源 java 项目中的一员,基于分层的 javaEE 应用一站式轻量级开源框架,主要核心是 Ioc(控制反转/依赖注入) 与 Aop(面向切面)两大技术,实现项目在开发过程中的轻松解耦,提高项目的开发效率。在项目中引入 spring 立即可以带来下面的好处 降低组件之间的耦合度,实现软件各层之间的解耦。可以使用容器提供的众多服务,如:事务管理服务、消息服务等等。当我们使用容器管理事务时,开发人员就不再需要手工控制事务.也不需处理复杂的事务传播。 容器提供单例模式支持,开发人员不再需要自己编写实现代码。 容器提供了 AOP 技术,利用它很容易实现如权限拦截、运行期监控等功能。

1.IOC : 控制翻转 (Inversion of Control)

IOC意味着将你设计好的对象交由控制器控制,而不是传统的在你的对象内部直接控制.,IOC控制了对象,应用程序被动的等待IOC容器来创建并注入它所需要的资源.

2.DI : 依赖注入 Dependency Injection

由容器动态的将某个依赖关系注入到组件中.依赖注入的目的并非是为软件系统带来更多的功能,而是为了提升组件重用的频率,并为系统搭建一个灵活的,可扩展的平台.

3.AOP : 面向切面编程

AOP技术利用一种称为”横切”的技术,破开封装的对象内部名,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为”Aspect”,即切面.所谓切面,简单来说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合多,并有利于未来的可操作性和可维护性.

AOP将软件系统分为两个部分:核心关注点和横切关注点.业务的主要处理流程是核心关注点,与之关系不大的部分是横斜关注点.横切关注点的一个特点是,他们经常发生在核心关注点多出,而各处基本相似,如权限认证,日志,事务.AOP的作用就是在于分离系统中的各种关注点,将核心关注点和横斜关注点分离开来.

Spring主要的6大模块

  1. 核心容器

  2. Spring-AOP

  3. Spring Data Access

  4. WEB模块

  5. Spring-message

  6. 测试单元

Spring框架环境搭建

环境要求:jdk 1.7 及以上、Spring 版本:4.3.2

新建项目

maven 创建普通 java 工程并调整整体工程环境(jre 编译器版本)

添加spring框架核心坐标

<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-context</artifactId>
	<version>4.3.9.RELEASE</version>
</dependency>

编写bean

package com.shsxt.service;
public class HelloService {
	public void hello(){
		System.out.println("hello spring");
	}
}

spring配置文件编写

在 src 下新建 xml 文件,并拷贝官网文档提供的模板内容到 xml 中,配置bean 到 xml 中,把对应 bean 纳入到 spring 容器来管理

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
    xmlns 即 xml namespace xml 使用的命名空间
    xmlns:xsi 即 xml schema instance xml 遵守的具体规范
    xsi:schemaLocation 本文档 xml 遵守的规范 官方指定
-->
<bean id="helloService" class="com.shsxt.service.HelloService"></bean>
</beans>

思考:Bean 是如何被实例化的?—工厂模式
Spring 的核心容器实现了 IOC, BeanFactory 和 ApplicationContext 是了解Spring 核心的关键。
Spring 中,两个最基本、最重要的包,org.springframework.beans 和org.springframework.context。框架中代码大量引用了 Java 中的反射机制,为Spring 的反向控制特性提供了基础。
BeanFactory 提供了一种配置机制来管理任何种类的 Bean
ApplicationContext 建立在 BeanFactory 之上,并增加了其他的功能,比如对国际化的支持、获取资源、事件传递等。
IOC 源码解析参考 http://www.cnblogs.com/ITtangtang/p/3978349.html

IOC容器简析

涉及的知识点:xml文件解析,xpath使用 dom4j 反射 集合

实现的功能:

1.读取xml配置文件

2.通过配置信息创建类的实例

3.存储实例和取出实例

Spring IOC实例化Bean对象的三种方式

1.构造器的方式实例化bean对象

<bean id="userServiceImpl"
class="com.shsxt.service.impl.UserServiceImpl"></bean>

通过默认构造器创建 空构造方法必须存在 否则创建失败

2.静态工厂方法实例化bean

特点:

​ 要有该工厂类及工厂方法

​ 工厂方法为静态

静态工厂定义

public class StaticFactory {
	public static UserService createUserService(){
		return new UserService();
	}
}	

Bean配置

<bean id="userService" class="com.shsxt.factory.StaticFactory"
factory-method="createUserService"/>

当我们指定Spring使用静态工厂方法来创建bean实例时,Spring将先解析配置文件,并根据配置文件指定的信息,通过反射调用静态工厂类的静态工厂方法,并将该静态工厂方法的返回值作为Bean实例.在这个过程中,Spring将不再负责Bean实例,Bean实例是由用户提供的静态工厂方法提供的

3.实例化化工厂方式创建bean

工厂方法为非静态方法

需要配置工厂Bean,并在业务bean中配置factory-bean,factory-method属性

实例化工厂定义

public class InstanceFactory {
	public UserService createUserService(){
		return new UserService();
	}
}

Bean配置

<!--实例化工厂
1.定义实例化工厂 bean
2.引用工厂 bean 指定工厂创建方法(方法为非静态)
-->
<bean id="instanceFactory" class="com.shsxt.factory.InstanceFactory"></bean>
<bean id="userService" factory-bean="instanceFactory" factory-method="createUserService"></bean>

spring 三种实例化 bean 的方式比较

方式一:通过 bean 的缺省构造函数创建,当各个 bean 的业务逻辑相互比较独立的时候或者和外界关联较少的时候可以使用。

方式二:利用静态 factory 方法创建,可以统一管理各个 bean 的创建,如各个 bean 在创建之前需要相同的初始化处理,则可用这个 factory 方法险进行统一的处理等等。

方式三:利用实例化 factory 方法创建,即将 factory 方法也作为了业务 bean 来控制,1 可用于集成其他框架的 bean 创建管理方法,2 能够使 bean 和 factory 的角色互换。

开发中项目一般使用一种方式实例化 bean,项目开发基本采用第一种方式,交给 spring 托管,使用时直接拿来使用即可。另外两种了解

Spring IOC注入

1.set注入

xml配置(同时Spring也提供了对于基本数据类型的set注入方式)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		xsi:schemaLocation="http://www.springframework.org/schema/beans
			http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userServiceImpl" class="com.shsxt.service.impl.UserServiceImpl">
	<property name="userDao" ref="userDao"></property>
</bean>
<bean id="userDao" class="com.shsxt.dao.UserDao"></bean>

Java类

public class UserServiceImpl {
    private UserDao userDao;
    public void setUserDao(UserDao userDao) {
    	this.userDao = userDao;
    } 
    public UserDao getUserDao() {
    	return userDao;
    } 
    public void saveUser(User user){
    	System.out.println("userName:"+userName+"price:"+price);
   		userDao.add(user);
    }
}

2.构造器注入

xml配置(也提供对于基本数据类型、字符串等值的注入 )

<bean id="userDao" class="com.shsxt.dao.UserDao"></bean>
	<bean id="userServiceImpl2"class="com.shsxt.service.impl.UserServiceImpl2">
	<constructor-arg ref="userDao"></constructor-arg>
</bean>

Java类 提供构造函数

public class UserServiceImpl2 {
    private UserDao userDao;
    public UserServiceImpl2(UserDao userDao) {
    	this.userDao = userDao;
    }
    public void saveUser(User user){
    	userDao.add(user);	
    }
}

3.静态工厂注入

<bean id="userDao" class="com.shsxt.factory.StaticFactory" factorymethod="createUserDao"></bean>
<bean id="userService" class="com.shsxt.service.UserService">
	<property name="userDao" ref="userDao"></property>
</bean>

静态工厂类

public class StaticFactory {
	public static UserDao createUserDao(){
		return new UserDao();
	}
}

4.实例化工厂

<bean id="sxtBeanFactory" class="com.shsxt.factory.SxtBeanFactory" >
<bean id="instanceFactory" class="com.shsxt.factory.InstanceFactory"></bean>
<bean id="userDao" factory-bean="instanceFactory" factorymethod="createUserDao"></bean>
<bean id="userService" class="com.shsxt.service.UserService">
	<property name="userDao" ref="userDao"></property>
</bean>

注入的选择:开发项目中set方式注入首选

注解方法注入Bean

对于bean的注入,除了使用xml配置以外,注解的配置简化开发,使程序看上去更加简洁.对于注解的解释,Spring对于注解有专门的解释器,对定义的注解进行解析,实现ban对象的注入,通过反射技术试下.

1.加入 spring-aop jar 包 spring-aop-4.3.2.RELEASE.jar

2.Xml 配置: 加入 context 命名空间 和 xsd 地址

3.添加<context:annotation-config/> 配置

对于Bean的注入常用注解类型

@Autowired 属性字段或 set 方法上
@Resource 属性字段上或 set 方法上

区别: @Autowired 默认按 bean 的类型匹配 可以修改 按名称匹配 和@Qualifier 配合使用
@Resource 默认按名称进行装配, 名称可以通过 name 属性进行指定, 如果没有指定 name 属性, 当注解写在字段上时, 默认取字段名进行匹配注入, 如果注解写在 setter 方法上默认取属性名进行装配。 当找不到与名称匹配的 bean时才按照类型进行装配。 但是需要注意的是,如果 name 属性一旦指定,就只会按照名称进行装配。
推荐使用@Resource 注解是属于 J2EE 的,减少了与 spring 的耦合。

Spring Ioc 容器自动扫描管理 bean

实际的开发中,bean 的数量非常多,采用手动配置 bean 的方式已无法满足生
产需要,spring 这时候同样提供了扫描的方式,对扫描到的 bean 对象统一进行管理,
简化开发配置,提高开发效率。

不在需要配置

<context:annotation-config/>

需要配置包扫描

<context:component-scan base-package="com.shsxt"/>

同时对于被 spring 管理的 bean 类的定义上需要加入对应的注解定义

Spring的四个注解

Dao层:@Repository

Service层:@service

Controller:@Controller

如果对于开发的类实在不明确是属于哪个层,使用@Component注解定义

Bean的作用域

默认情况下,我们从Spring容器中拿到的对象均是单例的,对于bean的作用域类型如下

1、 singleton 作用域

容器在启动的情况下就实例化所有 singleton 的 bean 对象,并缓存与容器中
单例的好处:
1)提前发现潜在的配置问题
2)Bean 对象存在于缓存中,使用时不用再去实例化 bean,加快程序运行效率

2、 prototype 作用域

通过 scope=” prototype” 设置 bean 的类型 ,每次向 Spring 容器请求获取
Bean 都返回一个全新的 Bean,相对于“singleton”来说就是不缓存 Bean,每次都是
一个根据 Bean 定义创建的全新 Bean

3 、Web 应用中的作用域(request、 session、 globalsession)

request 作用域:表示每个请求需要容器创建一个全新 Bean。比如提交表单的数据必须是对每次请求新建一个 Bean 来保持这些表单数据,请求结束释放这些数据。

session 作用域:表示每个会话需要容器创建一个全新 Bean。比如对于每个用户一般会有一个会话,该用户的用户信息需要存储到会话中,此时可以将该 Bean 作用域配置为 session 级别。

globalSession:类似于 session 作用域,其用于 portlet(Portlet 是基于 Java的 Web 组件,由 Portlet 容器管理,并由容器处理请求,生产动态内容)环境的 web 应用。如果在非 portlet 环境将视为 session 作用域。

Bean的生命周期

在Spring中,Bean的生命周期包括Bean的定义,初始化,使用和销毁四个阶段.

Bean的初始化

Bean的初始化有两种方法:

I.在配置文档中通过指定 init-method 属性来完成。
II.实现 org.springframework.beans.factory.InitializingBean 接口。

Bean 的使用

I.使用 BeanFactory
II.使用 ApplicationContext

Bean 的销毁

实现销毁方式(spring 容器会维护 bean 对象的管理,可以指定 bean 对象的销毁所要执行的方法)
通过 AbstractApplicationContext 对象,调用其 close 方法实现 bean 的销毁过程。

代理模式

代理模式在 java 开发中是一种比较常见的设计模式。 设计目的旨在为服务类与客户类之间插入其他功能, 插入的功能对于调用者是透明的, 起到伪装控制的作用。

代理模式的两个设计原则:

  1. 代理类 与委托类具有相似的行为(共同)
  2. 代理类增强委托类的行为

静态代理

为某个对象提供一个代理, 代理角色固定, 以控制对这个对象的访问。代理类和委托类有共同的父类或父接口, 这样在任何使用委托类对象的地方都可以用代理对象替代。 代理类负责请求的预处理、 过滤、 将请求分派给委托类处理、 以及委托类执行完请求后的后续处理

动态代理

相比于静态代理, 动态代理在创建代理对象上更加的灵活, 它会根据需要通过反射机制在程序运行期动态的为目标对象创建代理对象, 代理的行为可以代理多个方法, 即满足生产需要的同时又达到代码通用的目的

动态代理的两种实现方式

1.jdk动态代理实现
/**
* jdk 动态代理
* *
/
public class JdkHandler implements InvocationHandler{
  // 目标类
  private Object target;
  public JdkHandler(Object target) {
  this.target = target;
  } /
  **
  * 程序运行期动态创建代理角色
  * @return
  */
  public Object getProxy(){
  /**
  * 获取代理对象
  * 1.类加载器
  * 2.目标类 实现的接口 class
  * 3.当前类
  * @return
  */
  return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
  } 
  public void before(){
    System.out.println("婚礼现场紧张布置中......");
  } 
  @Override
  public Object invoke(Object proxy, Method method, Object[]
  args)throws Throwable {
    before();//增强真实角色行为
    Object result= method.invoke(target, args);// 执行真实角色方法
    after();//增强真实角色行为
    return result;
  } 
  public void after(){
    System.out.println("恭喜您成功进入人生第二阶段.....");
  }
}
2.cglib动态代理实现

code generator library , 操作字节码。 与 jdk 提供的代理区别, Proxy: 委托类必须有接口, 制作过程比较快, 执行慢; cglib: 委托类可以没有接口, 继承的思维来实现相似性, 制作代理过程比较慢, 执行快。 主要解决没有接口类的代理实现。

public class CglibInterceptor implements MethodInterceptor {
  private Object target;
  public CglibInterceptor(Object target) {
    this.target = target;
  }
  // 运行期动态创建代理类
  public Object getProxy(){
    Enhancer enhancer=new Enhancer();
    //设置父类 class
    enhancer.setSuperclass(target.getClass());
    enhancer.setCallback(this);
    return enhancer.create();
  } 
  public void before(){
    System.out.println("婚礼现场紧张布置中......");
  } 
  @Override
  public Object intercept(Object arg0, Method arg1, Object[]
  arg2,MethodProxy arg3) throws Throwable {
    before();//增强真实角色行为
    Object result= arg3.invoke(target, arg2);
    after();//增强真实角色行为
    return result;
  } 
  public void after(){
    System.out.println("恭喜您成功进入人生第二阶段.....");
  }
}

AOP(jdk+cglib)

AOP是什么?

​ Aspect Oriented Programing面向切面编程,相比较oop,面向切面编程来说,Aop关注的不再是程序代码中的某个类,某些方法,而Aop考虑的更多的是一种面到面的切入,即层与层之间的一种切入,所以称之为切面.

AOP能做什么?

​ Aop主要用于日志记录,性能统计,安全控制,事务处理等方面,实现公共功能性的重复使用.

AOP的好处?

  • 降低模块之间的耦合度,提高业务代码的聚合度.(高内聚,低耦合)
  • 提高了代码的复用性
  • 提高系统的扩展性

AOP的基本概念

JoinPoint(连接点)

​ 被拦截到的每个点,Spring中指被拦截到的每一个方法,Spring Aop一个连接点即代表一个方法的执行.

Pointcut(切入点)

​ 对连接点进行拦截的定义(匹配股则定义:规定拦截哪些方法,对哪些方法进行处理),spring这块有专门的表达式定义语言

Advice(通知)

​ 拦截到每一个连接点即(每一个方法)后需要做的操作

​ i. 前置通知 (前置增强) --before() 执行方法前通知
​ ii.返回通知(返回增强)–afterReturn 方法正常结束返回后的通知
​ iii.异常抛出通知(异常抛出增强)–afetrThrow()
​ iv.最终通知—after 无论方法是否发生异常,均会执行该通知。
​ v.环绕通知—around 包围一个连接点(join point)的通知,如方法调用。这是最强大的一种通知类型。 环绕通知可以在方法调用前后完成自定义的行为。它也会选择是否继续执行连接点或直接返回它们自己的返回值或抛出异常来结束执行。

Aspect(切面)

​ 切入点与通知的结合,决定了切面的定义,切入点定义了要拦截哪些类哪些方法,通知则定义了拦截过后要做什么,切面则是横切关注点的抽象,与类相似,类是对物体特征的抽象,切面则是横切关注点抽象.

Target(目标对象)

​ 被代理的目标对象

Weave(织入)

​ 将切面应用到目标对象并生产代理对象的这个过程即为织入.

Introduction(引入)

​ 在不修改原有应用程序代码的情况下,在程序运行期为类动态添加方法或者字段的过程称为引入.

AOP匹配方法规则表达式语言

​ Aop切入点表达式简介

​ 执行任意公共方法:

execution(public *(..))

​ 执行任意的 set 方法

execution(* set*(..))

​ 执行 com.xyz.service 包下任意类的任意方法

execution(* com.xyz.service..(..))

​ 执行 com.xyz.service 包 以及子包下任意类的任意方法

execution(* com.xyz.service...(..)) 

Spring定时任务

基于xml方式定时任务的配置

1.定时任务命名空间的添加

xmlns:task="http://www.springframework.org/schema/task"
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task.xsd

2.定时任务方法的代码

@Component
public class TaskSchedule {
    public void job1(){
    System.out.println("任务 1:"+new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date()));
    }
    public void job2(){
   	 System.out.println("任务 2:"+new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date()));
    }
}

3.定时任务配置

<task:scheduled-tasks>
	<!-- 每个两秒执行一次任务 -->
	<task:scheduled ref="taskSchedule" method="job1" cron="0/2 * * * * ?"/>
	<!-- 每隔五秒执行一次任务 -->
	<task:scheduled ref="taskSchedule" method="job2" cron="0/5 * * * * ?"/>
	<!-- 多个定时任务 在这里配置 -->
</task:scheduled-tasks>	

基于注解的方式配置定时任务

1.在配置文件中添加命名空间

xmlns:task=http://www.springframework.org/schema/task
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-3.0.xsd

2.配置定时任务驱动

<task:annotation-driven />

3.定时任务代码

@Component
public class TaskSchedule {
	@Scheduled(cron="0/2 * * * * ?")	
	public void job1(){
		System.out.println("任务 1:"+new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new 		Date()));
}

    @Scheduled(cron="0/5 * * * * ?")
    public void job2(){
		System.out.println("任务 2:"+new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date()));
	}
}

Cron表达式简介

关于 cronExpression 表达式有至少 6 个(也可能是 7 个) 由空格分隔的时间元素。 从左至右, 这些元素的定义如下:

  • 1. 秒(0–59)
  • 2. 分钟(0–59)
  • 3. 小时(0–23)
  • 4. 月份中的日期(1–31)
  • 5. 月份(1–12 或 JAN–DEC)
  • 6. 星期中的日期(1–7 或 SUN–SAT)
  • 7. 年份(1970–2099)

一些例子

"0 0 12 * * ?"每天中午十二点触发
"0 15 10 ? * *"每天早上 10: 15 触发
"0 15 10 * * ?"每天早上 10: 15 触发
"0 15 10 * * ? *"每天早上 10: 15 触发
"0 15 10 * * ? 2005" 2005 年的每天早上 10: 15 触发 
"0 * 14 * * ?"每天从下午 2 点开始到 2 点 59 分每分钟一次触发
"0 0/5 14 * * ?"每天从下午 2 点开始到 2: 55 分结束每 5 分钟一次触发
"0 0/5 14,18 * * ?"每天的下午 2 点至 2: 55 和 6 点至 6 点 55 分两个时间段内每 5 分钟一次触发
"0 0-5 14 * * ?"每天 14:00 至 14:05 每分钟一次触发
"0 10,44 14 ? 3 WED"三月的每周三的 14: 10 和 14: 44 触发
"0 15 10 ? * MON-FRI"每个周一、 周二、 周三、 周四、 周五的 10: 15 触发
"0 15 10 15 * ?"每月 15 号的 10: 15 触发
"0 15 10 L * ?"每月的最后一天的 10: 15 触发
"0 15 10 ? * 6L"每月最后一个周五的 10: 15 

JAVA邮件发送

JavaMail 是由 Sun 定义的一套收发电子邮件的 API, 不同的厂商可以提供自己的实现类。 但它并没有包含在 JDK 中, 而是作为 JavaEE 的一部分。厂商所提供的 JavaMail 服务程序可以有选择地实现某些邮件协议

常见的邮件协议包括:

SMTP: 简单邮件传输协议, 用于发送电子邮件的传输协议;
POP3: 用于接收电子邮件的标准协议;
IMAP: 互联网消息协议, 是 POP3 的替代协议。
MIME:多用途因特网邮件扩展标准。
这三种协议都有对应 SSL 加密传输的协议, 分别是 SMTPS, POP3S 和 IMAPS。

JavaMail 的关键对象

Properties: 配置信息
Session: 一个会话
Transport和Store: 传输 存储
Message:消息对象(发件人 收件人 时间 标题 内容 附件)
Address:地址
Authenticator:认证者

Java mail发送邮件

准备环境,添加依赖,注册邮箱,开放授权码

<dependency>
      <groupId>javax.mail</groupId>
      <artifactId>mail</artifactId>
      <version>1.4</version>
    </dependency>

发送普通文本邮件

  // 定义邮箱服务器配置
        Properties props=new Properties();
        // 163 邮件服务器地址
        props.put("mail.smtp.host", "smtp.163.com");
        // 163 邮件服务器端口
        props.put("mail.smtp.port", "25");
        // 163 邮件服务器认证属性
        props.put("mail.smtp.auth", "true");// 字符串true

        Session session = Session.getDefaultInstance(
                props,new MyAuthenticator("jioc19940812@163.com","ch199476"));// 授权码

        // 创建消息
        Message message = new MimeMessage(session);
        // 设置发件人
        message.setFrom(new InternetAddress("jioc19940812@163.com"));
        // 设置收件人
        message.setRecipient(Message.RecipientType.TO,new InternetAddress("jioc19940812@163.com"));

        //设置消息内容(时间/主题/内容)
        message.setSentDate(new Date());
        message.setSubject("邮箱测试");
        message.setText("我是一个简单的文本邮件");

        // 发送
        Transport.send(message);

发送html邮件

  // 创建消息
        Message message = new MimeMessage(session);
        // 设置发件人
        message.setFrom(new InternetAddress("jioc19940812@163.com"));
        // 设置收件人
        message.setRecipient(Message.RecipientType.TO,new InternetAddress("jioc19940812@163.com"));

        //设置消息内容(时间/主题/内容)
        message.setSentDate(new Date());
        message.setSubject("邮箱测试");

        MimeMultipart mimeMultipart = new MimeMultipart();
        MimeBodyPart mimeBodyPart = new MimeBodyPart();

        StringBuffer sb = new StringBuffer();
        sb.append("<html><body><a href='http://www.baidu.com'>百度一下</a></body></html>");

        mimeBodyPart.setContent(sb.toString(),"text/html;charset=utf-8");
        mimeMultipart.addBodyPart(mimeBodyPart);

        message.setContent(mimeMultipart);

发送附件邮件

//设置消息内容(时间/主题/内容)
        message.setSentDate(new Date());
        message.setSubject("邮箱测试");

        MimeMultipart mimeMultipart = new MimeMultipart();
        MimeBodyPart mimeBodyPart = new MimeBodyPart();

        StringBuffer sb = new StringBuffer();
        sb.append("<html><body><a href='http://www.baidu.com'>百度一下</a></body></html>");

        mimeBodyPart.setContent(sb.toString(),"text/html;charset=utf-8");
        mimeMultipart.addBodyPart(mimeBodyPart);

        // 添加附件
        BodyPart mimeBodyParts = new MimeBodyPart();
        // 读取附件
        FileDataSource fileDataSource = new FileDataSource(new File("D:\\project\\mailTest\\readme.txt"));
        // 设置附件
        mimeBodyParts.setDataHandler(new DataHandler(fileDataSource));
        // 设置附件标题
        mimeBodyParts.setFileName(MimeUtility.encodeText("readme.txt"));

        mimeMultipart.addBodyPart(mimeBodyParts);

        message.setContent(mimeMultipart);

Spring整合mail

环境准备,添加依赖

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- spring 核心 jar 依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<!-- spring 上下文环境 支持 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<!-- java mail 坐标依赖 -->
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4.7</version>
</dependency>
</dependencies>

配置文件配置邮件发送bean

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="mailSender"
class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="host" value="smtp.163.com" />
<property name="port" value="25" />
<property name="defaultEncoding" value="utf-8"></property>
<property name="username" value="shsxt_test@163.com"></property>
<property name="password" value="1qaz2wsx"></property>
<property name="javaMailProperties">
<props>
<prop key="mail.smtp.auth">true</prop>
</props>
</property>
</bean>
<!-- this is a template message that we can pre-load with default state -->
<bean id="templateMessage"
class="org.springframework.mail.SimpleMailMessage">
<property name="from" value="shsxt_test@163.com" />
<property name="subject" value="spring_mail" />
</bean>
<bean id="orderManager" class="com.shsxt.test.SimpleOrderManager">
<property name="mailSender" ref="mailSender" />
<property name="templateMessage" ref="templateMessage" />
</bean>
</beans>

发送接口定义与实现

/**
* 发送邮件接口定义
* @author lp
* *
/
public interface OrderManager {
	void placeOrder();
} 
	
public class SimpleOrderManager implements OrderManager {
    private MailSender mailSender;
    private SimpleMailMessage templateMessage;
    public void setMailSender(MailSender mailSender) {
    	this.mailSender = mailSender;
    }
    public void setTemplateMessage(SimpleMailMessage templateMessage) {
		this.templateMessage = templateMessage;
} 
	public void placeOrder() {
		SimpleMailMessage msg = new SimpleMailMessage(this.templateMessage);
		msg.setTo("shsxt_test@163.com");
		msg.setText("test...asdasdasdsd");
		try{
			this.mailSender.send(msg);
		} catch (MailException ex) {
			System.err.println(ex.getMessage());
		}
	}
}

发送邮件附件,xml配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="mailSender"
class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="host" value="smtp.163.com" />
<property name="port" value="25" />
<property name="defaultEncoding" value="utf-8"></property>
<property name="username" value="shsxt_test@163.com"></property>
<property name="password" value="1qaz2wsx"></property>
</bean>
</beans>

Spring整合JDBC

连接池

作用:在系统启动时就提前创建好指定连接,供调用。不用每次数据库请求都新建连接和 关闭接。
常用的两个连接池:c3p0(可以自动关闭空闲连接)和dbcp(不可以自动关闭空闲连接)

添加依赖

<!-- mysql 驱动包 -->
<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <version>5.1.39</version>
</dependency>
<!-- c3p0 连接池 -->
<dependency>
  <groupId>c3p0</groupId>
  <artifactId>c3p0</artifactId>
  <version>0.9.1.2</version>
</dependency>
<!-- spring jdbc -->
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-jdbc</artifactId>
  <version>4.3.2.RELEASE</version>
</dependency>
<!-- spring事物 -->
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-tx</artifactId>
  <version>4.3.2.RELEASE</version>
</dependency>

配置spring.xml文件

<!--包扫描-->
<context:component-scan base-package="com.shsxt"/>
<!-- 加载properties 配置文件 -->
<context:property-placeholder location="db.properties" />

<!-- 配置c3p0 数据源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <property name="driverClass" value="${jdbc.driver}"></property>
    <property name="jdbcUrl" value="${jdbc.url}"></property>
    <property name="user" value="${jdbc.user}"></property>
    <property name="password" value="${jdbc.password}"></property>
</bean>

<!-- jdbcTemplate 配置 -->
<bean id="jdbcTemplate"  class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="dataSource"></property>
</bean>

添加数据库配置文件(jdbc.properties)

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/aitao?useUnicode=true&characterEncoding=utf8
jdbc.user=root
jdbc.password=0000

新建po类

private Integer id;
private String aname;
private String type;
private Double money;
private Integer userId;
private Date createTime;
private Date updateTime;
private String remark;
//需要设置相对应的getter和setter方法

实现功能(添加用户)

@Autowired
private JdbcTemplate jdbcTemplate;

@Override
public int addAccountNoKey(Account account) {
    String sql = "insert into account (aname,type,money,remark,user_id,create_time,update_time)"
            +"values(?,?,?,?,?,?,?)";
    Integer result = jdbcTemplate.update(sql,account.getAname(),account.getType(),account.getMoney(),
            account.getType(),account.getUserId(),account.getCreateTime(),account.getUpdateTime());
    return result;
}

(添加用户并返回主键)

@Override
public int addAccountHasKey(Account account) {
    String sql="insert into account(aname,type,money,remark,user_id,create_time,update_time)"
            + " values(?,?,?,?,?,?,?)";
    // 定义keyHolder 对象  用户获取记录主键值
    KeyHolder keyHolder = new GeneratedKeyHolder();
    jdbcTemplate.update(new PreparedStatementCreator() {
        @Override
        public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {
            //  获取PreparedStatement  并设置参数
            PreparedStatement ps = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
            ps.setString(1,account.getAname());
            ps.setString(2, account.getType());
            ps.setDouble(3, account.getMoney());
            ps.setString(4, account.getRemark());
            ps.setInt(5, account.getUserId());
            ps.setObject(6, account.getCreateTime());
            ps.setObject(7, account.getUpdateTime());
            return ps;
        }

    },keyHolder);
    // 返回主键
    return keyHolder.getKey().intValue();
}

远程方法调用RMI

Java RMI指的是远程方法调用。他是一种机制,能够让在某个java虚拟机上的对象调用另一个java虚拟机中对象中的法。

Java RMI极大的依赖于接口,在需要创建一个远程对象的时候,程序通过传递程序员通过传递一个接口来隐藏底层的实现细节, 客户端得到的远程对象句柄正好与本地的根代码连接, 由后者负责透过网络通信。

RMI实现常用API

Remote接口:每一个要暴露出去的java类,都需要实现Remote接口,并且所有方法必须抛出RemoteException

UnicastRemoteObject类:服务器端程序的实现方式之一就是继承这个类,无参构造器也要抛出RemoteException

LocateRegistry类创建能在特定接口接收远程对象注册服务程序。

public static Registry createRegistry(int port) throws RemoteException

Naming类提供了存储和获得远程对象注册服务程序中的远程对象进行引用的方法

public static Remote lookup(String name) throws NotBoundException,MalformedURException,ReoteException

public static void bind(String name,Remote obj) throws
AlreadyBoundException,MalforedURException,RemoteException

远程调用实例

服务器端

接口定义

/**
* 1.接口继承 Remote
* 2.对外服务方法声明 RemoteException 异常
* *
/
public interface IHelloService extends Remote{
	public String sayHello(String msg) throws RemoteException;
}

接口类具体服务实现类

/**
* 1、 继承 UnicastRemoteObject
* 2、 提供 无参构造 对外声明 RemoteException
* *
/
public class HelloServiceImpl extends UnicastRemoteObject implements IHelloService {
    private static final long serialVersionUID = -5672932066566630040L;
    public HelloServiceImpl() throws RemoteException {} 
    @Override
    public String sayHello(String msg) throws RemoteException{
        System.out.println("服务器端接收到消息: "+msg);
        return "hello:"+msg;
    }
}

发布服务,对外提供相应服务

public class Publish {
    public static void main(String[] args) throws RemoteException,
        MalformedURLException, AlreadyBoundException {
        //注册端口
        LocateRegistry.createRegistry(8888);
        //对外发布 rmi 服务
        Naming.bind("rmi://127.0.0.1:8888/hello", new  HelloServiceImpl());
    }
}

客户端

客户端与服务端声明相同接口

public interface IHelloService extends Remote{
	public String sayHello(String msg) throws RemoteException;
}	

客户端查找并调用远程服务

public class Test {
    public static void main(String[] args) throws
        MalformedURLException, RemoteException, NotBoundException {
        IHelloService helloService=(IHelloService)
        Naming.lookup("rmi://127.0.0.1:8888/hello");
        System.out.println(helloService.sayHello("im win10"));
    }
}

Spring实现远程方法调用

使用spring的RMI,提供的服务简单方便,不用继承接口和指定的类,不用抛出异常

服务器端接口声明

接口声明

public interface IHelloService {
	public String sayHello(String msg);
}

接口实现

@Service
public class HelloServiceImpl implements IHelloService {
    @Override
    public String sayHello(String msg) {
        System.out.println("服务器端收到信息: "+msg);
        return "hello:"+msg;
    }
}

Xml配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/springcontext.xsd">
<!-- 定义扫描范围 -->
<context:component-scan basepackage="com.shsxt"></context:component-scan>
<!-- 加入 rmi 相关配置 -->
<bean class="org.springframework.remoting.rmi.RmiServiceExporter">
<property name="serviceName" value="hello"></property>
<property name="service" ref="helloServiceImpl"></property>
<property name="serviceInterface"
value="com.shsxt.service.IHelloService"></property>
<property name="registryPort" value="1199"></property>
</bean>
</beans>

对外发布远程服务

public class Publist {
    public static void main(String[] args) {
        /**
        * 启动 spring ioc 容器 , 并发布对应服务
        */
        ApplicationContext ac=new
        ClassPathXmlApplicationContext("beans.xml");
    }
}

客户端调用

接口声明

public interface IHelloService {
	public String sayHello(String msg);
}

Xml配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/springcontext.xsd">
<!-- 定义扫描范围 -->
<context:component-scan basepackage="com.shsxt"></context:component-scan>
<bean class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
<property name="serviceUrl"
value="rmi://localhost:1199/hello"></property>
<property name="serviceInterface"
value="com.shsxt.service.IHelloService"></property>
</bean>
</beans>

客户端使用远程接口方法服务

@Service
public class UserServiceImpl {
    @Resource
    private IHelloService helloService;
    public void test(){
    	System.out.println(helloService.sayHello("im win10"));
    }
}

客户端测试

public class Test {
    public static void main(String[] args) {
        ApplicationContext ac=new ClassPathXmlApplicationContext("beans.xml");
        UserServiceImpl userServiceImpl= (UserServiceImpl)
        ac.getBean("userServiceImpl");
        userServiceImpl.test();
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值