ssm整合
目录
SSM (spring \ springmvc \mybatis)
数据层 - mybatis
表现层 - springmvc
业务层 - 由需求决定
spring 是在三层之间进行整合的基础架构
spring做底,其他东西都在spring上运行
spring -- 搭框架基础
MyBatis -- mysql + druid + pagehelper
Spring 整合 MyBatis --加上 Junit 测试业务层接口
SpringMVC --rest风格(postman测试请求结果)、数据封装json
Spring 整合 SpringMVC -- Controller 能调用Service
基于springmvc的表现层技术、调用业务层、再调数据层
整个由spring做整体的项目总控
1、项目结构搭建
Java三层架构
注意:
1.1 实体类实现 Serializable 接口
1.2 数据层操作不要和业务层操作的名称混淆,通常数据层仅反映与数据库间的信息交换,不体现业务逻辑
1.3 列如 :数据层 getByUserNameAndPassword 业务层 login
2、spring整合mybatis
2.1 创建MyBatis映射文件
相关注意:dao层类中方法传参问题 两个参数以上加@Param
public User getByUserNameAndPassword(@Param("userName") String userName,@Param("password")String password);
2.2 创建Spring配置文件 - 组件扫描
相关注意:service层类中方法:分页查询
@Service中 @Autowired (注入dao)
查询使用分页查询
@Override
public PageInfo<User> getAll(int page, int size) {
PageHelper.startPage(page,size);
List<User> all = userDao.getAll();
return new PageInfo<User>(all);
}
2.3 整合mybatis到spring环境中
2.3.1 SqlSessionFactoryBean
2.3.1.1 数据源(druid + jbdc.properties)
2.3.2 映射扫描
!+++++++++!
2.3.3 注解事务
2.3.4 分页插件
<context:component-scan base-package="com.itheima">
<!--排除controller包下的bean-->
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!--加载properties文件-->
<context:property-placeholder location="classpath*:jdbc.properties"/>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!--整合mybatis到spring中-->
<bean class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="typeAliasesPackage" value="com.itheima.domain"/>
<!--分页插件 - 原理 : 在查询的内容的基础上进行了一些功能的增强-->
<!--private Interceptor[] plugins;-->
<property name="plugins">
<!--public void setPlugins(Interceptor... plugins) {
要参数拦截器 ...多个参数
this.plugins = plugins;
}-->
<array>
<!--拦截器-->
<bean class="com.github.pagehelper.PageInterceptor">
<property name="properties">
<!--要Properties类型的,怎么注入? -->
<!--使用 spring 提供的<prop>为Java持久属性集注入值,也就是向 java.util.Properties 对象中注入值。-->
<props>
<prop key="helperDialect">mysql</prop>
<prop key="reasonable">true</prop>
</props>
</property>
</bean>
</array>
</property>
</bean>
<!--映射扫描-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.itheima.dao"/>
</bean>
<!--在业务层接口上开事务管理器-->
<!--开启注解驱动-->
<tx:annotation-driven transaction-manager="txManager"/>
<!--创建事务管理器 - 使用jdbc的事务管理器-->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
开启事务
@Transactional(readOnly = true)//只读事务
public interface UserService {
@Transactional(readOnly = false) //读写事务
public boolean save(User user);
}
2.4 创建单元测试
Junit测试业务层接口
package com.itheima.service; //对service包下的类进行测试
//1、Junit专用的类加载器
@RunWith(SpringJUnit4ClassRunner.class)
//2、指定配置文件
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class UserServiceTest {
//注入要测试的接口
@Autowired
private UserService userService;
//测试方法
@Test
public void testSave(){
User user = new User();
user.setUserName("Nami");
user.setPassword("root");
user.setRealName("娜美");
user.setGender(0);
user.setBirthday(new Date(123456789L));
userService.save(user);
}
}
3、SpringMVC
3.1 web.xml 加载SpringMVC
3.1.1 创建spring-mvc.xml
<!--开启注解扫描-->
<mvc:annotation-driven/>
<!--加载controller包下的所有东西-->
<!--默认情况下,<context:component-scan>查找使用构造型(stereotype)注解所标注的类,
如@Component(组件),@Service(服务),@Controller(控制器),@Repository(数据仓库)。-->
<context:component-scan base-package="com.itheima.controller"/>
3.1.2 加载
<!-- 中文过滤-->
<filter>
<filter-name>CharacterEncodingFilter</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>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 加载文件-->
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:spring-mvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
3.2 rest风格
@RestController
@RequestMapping("/user")
public class UserController {
@GetMapping("/{uuid}")
public User get(@PathVariable Integer uuid){
System.out.println("get ..." + uuid);
return null;
}
@PostMapping
public boolean save(User user){
System.out.println("save ..." + user);
return true;
}
@PutMapping
public boolean update(User user){
System.out.println("update ..." + user);
return true;
}
@DeleteMapping("/{uuid}")
public boolean delete(@PathVariable Integer uuid){
System.out.println("delete ..." + uuid);
return true;
}
//注意 : 传两个
@GetMapping("/{page}/{size}")
public List getAll(@PathVariable Integer page, @PathVariable Integer size){
System.out.println("getAll ..." + page+","+size);
return null;
}
//注意 :登录 发post请求
@PostMapping("/login")
public User login(String userName,String password){
System.out.println("login ..." + userName + " ," +password);
return null;
}
}
3.3 数据封装为json数据
4、Spring整合SpringMVC
4.1 web.xml 加载Spring环境
<!--加载哪一个配置文件-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:applicationContext.xml</param-value>
</context-param>
<!-- 启动服务器时,通过监听器加载spring运行环境-->
<!--加载到ServletContext的上下文中-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
4.2 Controller调用Service
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@PostMapping
public boolean save(User user){
return userService.save(user);
}
@PutMapping
public boolean update(User user){
return userService.update(user);
}
@DeleteMapping("/{uuid}")
public boolean delete(@PathVariable Integer uuid){
return userService.delete(uuid);
}
@GetMapping("/{uuid}")
public User get(@PathVariable Integer uuid){
return userService.get(uuid);
}
@GetMapping("/{page}/{size}")
public PageInfo<User> getAll(@PathVariable Integer page, @PathVariable Integer size){
return userService.getAll(page,size);
}
@PostMapping("/login")
public User login(String userName,String password){
return userService.login(userName,password);
}
}
5、表现层数据封装
返回数据格式 状态 、 数据 、消息
package com.itheima.controller.results;
public class Result {
// 操作结果编码
private Integer code;
// 操作数据结果
private Object data;
// 消息
private String message;
public Result(Integer code) {
this.code = code;
}
public Result(Integer code, Object data) {
this.code = code;
this.data = data;
}
// get/set
}
package com.itheima.controller.results;
public class Code {
// 操作结果编码
public static final Integer SAVE_OK = 20011;
public static final Integer UPDATE_OK = 20021;
public static final Integer DELETE_OK = 20031;
public static final Integer GET_OK = 20041;
public static final Integer SAVE_ERROR = 20010;
public static final Integer UPDATE_ERROR = 20020;
public static final Integer DELETE_ERROR = 20030;
public static final Integer GET_ERROR = 20040;
// 系统错误编码
// 操作权限编码
// 校验结果编码
}
使用
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@PostMapping
public Result save(User user) {
boolean flag = userService.save(user);
return new Result(flag ? Code.SAVE_OK : Code.SAVE_ERROR);
}
@PutMapping
public Result update(User user) {
boolean flag = userService.update(user);
return new Result(flag ? Code.UPDATE_OK : Code.UPDATE_ERROR);
}
@DeleteMapping("/{uuid}")
public Result delete(@PathVariable Integer uuid) {
boolean flag = userService.delete(uuid);
return new Result(flag ? Code.DELETE_OK : Code.DELETE_ERROR);
}
@GetMapping("/{uuid}")
public Result get(@PathVariable Integer uuid) {
User user = userService.get(uuid);
return new Result(null != user ? Code.GET_OK : Code.GET_ERROR, user);
}
@GetMapping("/{page}/{size}")
public Result getAll(@PathVariable Integer page, @PathVariable Integer size) {
PageInfo<User> all = userService.getAll(page, size);
return new Result(null != all ? Code.GET_OK : Code.GET_ERROR, all);
}
@PostMapping("/login")
public Result login(String userName, String password) {
User user = userService.login(userName, password);
return new Result(null != user ? Code.GET_OK : Code.GET_ERROR, user);
}
}
6、问题消息处理
异常信息要和正常的返回信息统一格式
package com.itheima.system.exception;
public class BusinessException extends RuntimeException {
//自定义异常中封装对应的错误编码,用于异常处理时获取对应的操作编码
private Integer code;
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public BusinessException(Integer code) {
this.code = code;
}
public BusinessException(String message, Integer code) {
super(message);
this.code = code;
}
public BusinessException(String message, Throwable cause,Integer code) {
super(message, cause);
this.code = code;
}
public BusinessException(Throwable cause,Integer code) {
super(cause);
this.code = code;
}
public BusinessException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace,Integer code) {
super(message, cause, enableSuppression, writableStackTrace);
this.code = code;
}
}
package com.itheima.controller.interceptor;
@Component
@ControllerAdvice //设置当前类为异常处理器类
public class ProjectExceptionAdivce {
@ExceptionHandler(BusinessException.class) //设置指定异常的处理方式
@ResponseBody //为了统一格式
//对出现异常的情况进行拦截,并将其处理成统一的页面数据结果格式
public Result doBusinessException(BusinessException e){
return new Result(e.getCode(),e.getMessage()); //e.getCode() - 上面定义的
}
}
使用
@GetMapping("/{uuid}")
public Result get(@PathVariable Integer uuid){
User user = userService.get(uuid);
//模拟出现异常,使用条件控制,便于测试结果
if (uuid == 10 ) throw new BusinessException("查询出错啦,请重试!",Code.GET_ERROR);
return new Result(null != user ?Code.GET_OK: Code.GET_ERROR,user);
}
结果
{
"code": 20040,
"data": "查询出错啦,请重试!",
"message": null
}
镜花水月