基本搭建和操作流程

一、SSM环境搭建

  1. 创建父工程
    Maven – heima_ssm空项目
  2. 创建子工程
    空模块:heima_ssm_dao、heima_ssm_domain、heima_ssm_service、heima_ssm_utils
    web框架:heima_ssm_web
  3. 父工程中导入pom文件

二、编写实体类

下面以商品查询为例:

在这里插入图片描述
在domain中编写实体类。
注意:

1
2
3
4
5
6
7
//package com.itheima.ssm.domain;
//Product.java
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm")
private Date tradeTime; // 发布时间
private String tradeTimeStr;
private Integer productStatus; // 状态 0 关闭 1 开启
private String productStatusStr;

比如发布时间在前端显示不能是一个Date,而应该是String,格式化的数据。方便页面展示。

三、编写业务接口

dao中编写接口。IproductDao,里面定义查询方法。

1
2
3
4
5
6
7
8
9
10
11
12
public interface IProductDao {
//根据id查询产品
@Select("select * from product where id=#{id}")
public Product findById(Integer id) throws Exception;

//查询所有的产品信息
@Select("select * from product")
public List<Product> findAll() throws Exception;

@Insert("insert into product(productNum,productName,tradeTime,productPrice,productDesc,productStatus) values(#{productNum},#{productName},#{tradeTime},#{productPrice},#{productDesc},#{productStatus})")
void save(Product product);
}

service中编写接口。IProductService,里面定义查询方法。

1
2
3
4
5
public interface IProductService {
public List<Product> findAll() throws Exception;

void save(Product product) throws Exception;
}

@Autowired的使用来消除 set ,get方法
在Impl包中编写接口实现类:productServiceImpl,对接口中的方法进行实现。@Autowired完成对IproductDao productDao属性的自动装配,通知可以通过productDao去完成。

1
2
3
4
5
6
7
8
9
10
11
@Service
@Transactional
public class ProductServiceImpl implements IProductService{
@Autowired
private IProductDao productDao;

@Override
public List<Product> findAll() throws Exception{
return productDao.findAll();
}
……

四、文件配置

放在ssm_web下resources中。

applicationContext.xml是spring的核心配置文件

  1. 在里面配置一下扫描的包(service、dao)
  2. spring整合mybatis
    实质就是用spring来管理sqlSeesionFactoryBean
    首先指定扫描数据库配置文件(db.properties),配置连接池,交给IOC管理
  3. 配置事务

spring-mvc.xml

  1. 配置扫描web
    指定扫描的是controller包下的内容,指定下视图解析器,静态资源是否被过滤,开启注解支持

web.xml

  1. 配置加载类路径的配置文件(contextConfig.location),完成核心spring加载工作,配置监听
  2. 配置dispatcherServlet
    就是当前springMVC框架所需要使用的Servlet

五、编写控制器

在web中,创建ProductController
通过controller,去调用service去查询出来。然后把查出来的所有商品信息封装到ModelAndView中,然后返回它,响应到浏览器端去展示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Controller
@RequestMapping("/product")
public class ProductController {
@Autowired
private IProductService productService;
//查询全部产品
@RequestMapping("/findAll.do")
@RolesAllowed("ROOT")
public ModelAndView findAll() throws Exception {
ModelAndView mv = new ModelAndView();
List<Product> ps = productService.findAll();
mv.addObject("productList", ps);
mv.setViewName("product-list1");
return mv;
}
}

注意:
在web包的webapp下的web.xml中,所有的servlet,在拦截的时候,拦截的是*.do,也就是所有controller只处理*.do这种请求,所以在当前的ProductController中,指定的路径是/findAll.do这样我们通过controller去调用service,service帮助我们去调用dao,完成我们想要的操作。

六、响应展示

在webapp下的pages目录中,存放的是jsp页面。 css、img、plugins放在webapp下。

注意:
对于ProductStatus和tradeTime属性需要处理一下。在Product中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 public String getProductStatusStr() {
if (productStatus != null) {
// 状态 0 关闭 1 开启
if(productStatus==0)
productStatusStr="关闭";
if(productStatus==1)
productStatusStr="开启";
}
return productStatusStr;
}
public String gettradeTimeStr() {
if(tradeTime!=null){
tradeTimeStr= DateUtils.date2String(tradeTime,"yyyy-MM-dd HH:mm:ss");
}
return tradeTimeStr;
}

七、运行

  1. 运行需要在web模块的pom.xml中加入tomcat的插件。
  2. 在IDEA中,配置一下Run/Debug Configuration:
    添加一个Maven,指定要运行的工程是heima_ssm_web,命令tomcat7:run
  3. 运行之前,在右侧点击maven,把整个工程重写clean,再install。对应自己的webApp工程也做同样操作。
  4. 运行。

分页展示——PageHelper

PageHelper是一个开源的mybatis分页插件。
使用方式:

  1. 导入依赖
    第一种:把相应的jar包都拷贝进工程中
    第二种:使用maven工具。
    把相关maven的依赖集成到工程的pom.xml中
  2. 配置
    如果没有使用Spring,就可以直接在mybatis配置plugins;
    如果mybatis已经交由spring管理了,这时候需要在spring的配置文件【applicationContext.xml】里面的sqlSessionFactoryBean下添加配置。
    配置中的参数设置
    比如reasonable,规范页码【最前面只能到1页,最后面也有限定】
  3. 使用
    在真正执行sql使用PageHelper来完成分页
    1
    2
    3
    4
    // pageNum页码值,pageSize每页显示条数
    PageHelper.startPage(page,size);
    // 中间不能有其他语句
    return ordersDao.findAll();

权限控制——Spring Security

在这里插入图片描述

Spring Security框架

Spring Security是spring项目组中用来提供安全认证服务的框架。
安全主要包括两个操作:

  1. 认证:登录判断用户名密码是否正确的过程
  2. 授权:一个用户是否有权限来执行某个功能,在到达授权判断之前,权限已经给这个用户分配了

Spring Security主要是把用户信息存在数据库,通过数据库操作去获取信息;也可以通过配置文件去读取信息。

项目使用

使用配置文件认证

  1. pom中导入Spring Security依赖
  2. web.xml文件中创建Filter
    springSecurityFilterChain 名字不能改
  3. Spring Security核心文件配置 里面有角色和权限设置

使用数据库认证

从数据库获取信息,进行授权和认证。
使用UserDetailsUserDetailsService来完成操作。
UserDetails是一个接口,SpringSecurity提供的,封装当前进行认证的用户信息
UserDetailsService接口,规范化了在做认证时的方法

在这里插入图片描述
springsecurity代替了controller的功能。它怎么知道要调用谁?是因为我们在配置文件spring-security中规定了要用userService这个bean【UserDetails实现类】。只要我们实现了UserDetailsService接口即可。但是我们userDao返回的是自己定义对象,而userService需要UserDetails对象。

用户登录的操作流程
在heima_ssm_service中定义一个IUserService,扩展UserDetailsService。在Impl中,定义一个UserServiceImpl,实现IUserService,重写方法。

1
2
3
4
5
6
7
8
// spring-security.xml
<!-- 切换成数据库中的用户名和密码 -->
<security:authentication-manager>
<security:authentication-provider user-service-ref="userService">
<!-- 配置加密的方式 -->
<security:password-encoder ref="passwordEncoder"/>
</security:authentication-provider>
</security:authentication-manager>

上面配置了我们当前的service是userService,它就会去到我们下面这里去找loadUserByUsername方法,把我们的用户名去进行验证。

1
2
3
4
5
6
7
8
9
10
// UserServiceImpl.java
@Service("userService")
@Transactional
public class UserServiceImpl implements IUserService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

}

}

然后就要去找dao。所以在dao中创建IUserDao

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public interface IUserDao {
// @Result指定获取信息类型
@Select("select * from users where username=#{username}")
@Results({
@Result(id=true,property = "id",column = "id"),
@Result(property = "username",column = "username"),
@Result(property = "email",column = "email"),
@Result(property = "password",column = "password"),
@Result(property = "phoneNum",column = "phoneNum"),
@Result(property = "status",column = "status"),
@Result(property = "roles",column = "id",javaType = java.util.List.class,many=@Many(select="com.itheima.ssm.dao.IRoleDao.findRoleByUserId"))

})
public UserInfo findByUsername(String username) throws Exception;

然后还需要在domain中创建userInfo(与数据库中的users对应)、Role、Permission类。

再在UserServiceImpl补全函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
 @Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserInfo userInfo = null;
try {
userInfo = userDao.findByUsername(username) ;
} catch (Exception e) {
e.printStackTrace();
}
//处理自己的用户对象封装成UserDetails
//User user = new User(userInfo.getUsername(),"{noop}"+userInfo.getPassword(),getAuthority(userInfo.getRoles()));
User user = new User(userInfo.getUsername(),userInfo.getPassword(),userInfo.getStatus()==0 ? false : true,true,true,true,getAuthority(userInfo.getRoles()));
return user;
}

SpringSecurity源码分析

SpringSecurity源码分析

问题

ProductServieImpl中,private IProductDao productDao;一直报错,说找不到productDao。
原因:在applicationContext.xml中,忘记配置扫描dao包了。

因为有约束存在,所以不能直接删除users表,如果要删除,要先把中间表删除,再去删用户表就可以了。

查询用户信息时,应该把角色也获取到,封装到list集合中。