web应用业务层升级为spring
restful api
动词 | 网址 | 操作目标 |
---|---|---|
GET | /student/input | 去学生信息录入界面 |
GET | /students | 返回学生信息列表 |
GET | /student/123 | 返回学生学号为123的信息记录 |
POST | /studnets | 保存学生信息 |
DELETE | /studnets/123 | 删除学号为123的学生信息 |
PUT | /students/123 | 更新学号为123的学生信息 |
注:GET和POST提交访问不同的方法(虽然方法映射地址相同)
需求
我们发现在Java业务层中经常要进行new操作,当大量用户访问服务器时,每个用户都需要new多个对象,每次对象使用之后都会被销毁,因此无法实现复用,这会占用大量的内存资源。
升级方向
将一些无参数类通过spring进行复用
主动获得依赖->主动控制
别人提供依赖->IOC:Inverse Of Control(反转控制)
DI:Dependency Injection(依赖注入)
IOC技术起到的作用:承接new这一操作的“外包”。
采用IOC技术后,Java类中不再自己new对象,而是把这一操作“外包”,IOC中提供了许多方法,我们经常使用的是“注入依赖”方法。
实现IOC的两种方式
- 通过构造方法获取
右键选择Source->Generate Constructor using Fields - 通过setter方法获取
- 通过“自动编织”注解
spring技术
spring基础
- spring core
- spring context
- spring beans
spring mvc
- controller存在于spring mvc容器中
- springmvc为子容器,spring上下文容器为父容器。当子容器找不到资源时,去父容器找。
具体升级步骤
Java类
- 在类中声明private变量,这些用于取代原来new的对象。
- 通过set方法获取可复用对象。
- 在web.xml文件中进行配置
- 在web.xml文件中添加“上下文加载监听器”
- 设定配置文件的全局路径
- 建立相应配置文件
- 将需要复用的类所在的包的路径粘贴至配置文件中,包名之间用逗号(英文符号)隔开
- 在对应的类前添加注解,使相应类被spring识别并创建可复用对象
- 在private对象前添加“自动编织”注解,使Java类可以实现“层层调用”
- private声明的都是接口类
- 添加注解用于识别标记的都是用来实现的“Imple类”
mybatis
- 通过在application-context.xml添加bean来配置mybatis
- 在pom.xml文件中添加相应坐标用于加载相应库
- 在src/main/resources下创建文件夹db用于存放数据库连接信息
- 在src/main/resources下创建文件夹mapper用于存放映射
- mapper文件中的命名空间需和dao接口一致(包路径+文件名(不带后缀))
- mapper中的映射名需要和dao接口中的方法名一一对应,且dao所在的包只留下dao接口,其他类需全部删除(或者将dao中的实现类中的注解删除)。
例子
pom.xml
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
<!--Spring java数据库访问包,在本例中主要用于提供数据源 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.21</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>2.0.0-alpha1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.mchange/mchange-commons-java -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>mchange-commons-java</artifactId>
<version>0.2.15</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.1</version>
</dependency>
</dependencies>
web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/application-context.xml</param-value>
</context-param>
<!-- springmvc提供了一个servlet,能够拦截所有的请求,也就是说所有的请求都经过它 其映射方式类似于 /* -> dispatcherServlet -->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/dispatcher-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<filter>
<filter-name>EncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>EncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>HiddenHttpMethodFiler</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<filter-mapping>
<filter-name>HiddenHttpMethodFiler</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
src/main/resources下的文件夹spring中的application-context.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"
xmlns:tx="http://www.springframework.org/schema/tx"
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/spring-context-4.3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
<!--1 引入属性文件,在配置中占位使用 -->
<context:property-placeholder location="classpath:db/db.properties" />
<!--2 配置C3P0数据源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<!--驱动类名 -->
<property name="driverClass" value="${mysql.driver}" />
<!-- url -->
<property name="jdbcUrl" value="${mysql.url}" />
<!-- 用户名 -->
<property name="user" value="${mysql.username}" />
<!-- 密码 -->
<property name="password" value="${mysql.password}" />
<!-- 当连接池中的连接耗尽的时候c3p0一次同时获取的连接数 -->
<property name="acquireIncrement" value="5"></property>
<!-- 初始连接池大小 -->
<property name="initialPoolSize" value="10"></property>
<!-- 连接池中连接最小个数 -->
<property name="minPoolSize" value="5"></property>
<!-- 连接池中连接最大个数 -->
<property name="maxPoolSize" value="20"></property>
</bean>
<!--3 sessionFatory的配置-->
<!-- 只要你启动spring,创建上下文容器,那么sqlSessionFatory的实例就创建了 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="typeAliasesPackage" value="mju.edu.hairdryerwork.domain"/>
<property name="configuration">
<bean class="org.apache.ibatis.session.Configuration">
<property name="mapUnderscoreToCamelCase" value="true"/>
</bean>
</property>
<!-- sql映射文件路径 -->
<property name="mapperLocations" value="classpath*:mapper/*Mapper.xml"></property>
</bean>
<!-- 自动扫描接口类,如果发现接口的名字和和某个mapper的namespace一致,那么就指导生成这个接口的实现,然后注入spring容器 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--指定会话工厂,如果当前上下文中只定义了一个则该属性可省去 -->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
<!-- 指定要自动扫描接口的基础包,实现接口 -->
<property name="basePackage" value="mju.edu.hairdryerwork.dao"></property>
</bean>
<!--
spring的启动,本质上就是创建一个上下文容器,容器中存放了大量可以被复用的JAVA类的实例。
有两种方法来决定哪些类的实例能够放入容器。
1. 注解方式声明,扫描后创建复用实例
2. 直接声明bean -->
<context:component-scan base-package="mju.edu.hairdryerwork.dao,mju.edu.hairdryerwork.service"></context:component-scan>
</beans>
控制器部分代码
@Controller
public class HairdryerController {
@Autowired
private HairdryerService hdrService = null;
// 构造方法参数获得
// public HairdryerController(HairdryerService hdrService) {
// super();
// this.hdrService = hdrService;
//}
// set方法获取
// public void setHdrService(HairdryerService hdrService) {
// this.hdrService = hdrService;
// }
@RequestMapping("/hdr/to_index")
public String test() throws Exception{
System.out.println("避免首页进入信息录入界面(html)中文乱码进行转跳");
return "redirect:/hdr/input";
}
@RequestMapping("/hdr/input")
public String toInput() throws Exception{
System.out.println("input!");
//返回一个视图,他的名字叫input_hairdryer
return "input_hairdryer.html";
}
@PostMapping("/hairdryers")
public String createHdr(Hairdryer hdr) throws Exception{
// System.out.println(hdr);
System.out.println("save!");
// HairdryerService hdrService = new HairdryerServiceImpl();
hdrService.addHairdryer(hdr);
return "redirect:/hairdryers";
}
用于实现的service的类中部分代码
@Service
public class HairdryerServiceImpl implements HairdryerService {
@Autowired
private HairdryerDao hdrDao = null;
// public void setHdrDao(HairdryerDao hdrDao) {
// this.hdrDao = hdrDao;
// }
@Override
public void addHairdryer(Hairdryer hdr) {
// HairdryerDao hdrDao = new HairdryerDaoJDBCImpl();
// HairdryerDao hdrDao = new HairdryerDaoMybatisImpl();
hdrDao.addHdr(hdr);
}
用于实现的Dao的类中部分代码
@Repository
//使用spring接管dao之后需要将该注解删除,或将本类删除
public class HairdryerDaoMybatisImpl implements HairdryerDao {
@Override
public void addHdr(Hairdryer hdr) {
// TODO Auto-generated method stub
// 新建一个SQL session
SqlSession session = MybatisUtils.getSession();
// 将对象通过session进行新增
// 括号中的字符串代表的是使用的映射条目全称, hdr是要导入数据库的实体
session.insert("mju.edu.hairdryerwork.domain.Hairdryermapper.addHdr", hdr);
// 将对数据库的修改进行提交
session.commit();
// 通过相应函数将session释放
MybatisUtils.closeSession(session);
}