手把手带你分析一个基于SSM的商城项目 | 巨详细!
零、SSM项目配置文件与项目启动的一些需知
1. 项目启动读取配置文件过程
在Tomcat运行SSM项目时,容器最开始会去读取容器的配置文件web.xml,首先读取如下图这两个内容。
然后,Web容器会生成ServletContext,这个ServletContext是整个SSM项目共享,这是一个全局对象,所有Servlet都可以访问到。
将<context-param>
的内容联系起来并发送给ServletContext。
容器根据<listener>
创建监听器,这个ContextLoaderListener就是用来监听ServletContext的变化,并根据<context-param>
加载applicationContext.xml文件。
2. 配置文件详解
我们使用了<context:annotation-config/>
能够简单的帮助我们自动完成相应bean的声明。
加载完applicationContext.xml之后,会扫描service层和dao层注解。 引入外部的属性配置文件 在applicationContext.xml中配置使用阿里巴巴Druid数据库连接池,后期需要可以在其中添加多个属性配置。 在 MyBatis 中,通过 SqlSessionFactoryBuilder来生成SqlSessionFactory ,最终来生成 SqlSession。我们引入 MyBatis-Spring 后, 让SqlSessionFactoryBean代替了SqlSessionFactoryBuilder生成SqlSessionFactory。
MapperScannerConfigurer能够自动帮我们装载SqlSessionFactory 或 SqlSessionTemplate所以我们没必要在applicationContext.xml中注入sqlSession和sqlSessionFactory。
下图为对dataSource进行事务管理和配置 Annotation 驱动,扫描@Transactional注解的类定义事务。 扫描这个controller包,让SpringMVC认为该包下带注解的是controller。 扩充注解驱动。 对静态资源进行放过,比如css,js,图片等。 有了该配置,可以实现文件上传功能。不然就要引入文件上传组件。 配置视图解析。
下面正式进入项目分析,觉得博主分析得还不错的记得点个赞哦~
一、项目结构介绍
dto层(也称为model、entity层),作用就是定义实体类,对数据表中的对象的映射。
dao层主要用来封装对数据库的新增,删除,查询,修改。叫做数据访问层。
service层,即服务层,相比Dao较高层次,可将多种方法封装起来。
controller层,controller调用前面3层,前端调用对应接口,对应controller层接受前端传来的参数,处理好的数据也是通过controller层传递到前端显示的。
util层,util是utiliy的缩写,是一个多功能,相当于工具的包,封装一些实用的方法和数据结构。
resources存放资源文件:这里applicationContext.xml是spring的配置文件,create.sql是数据库脚本,generatorConfig.xml是引入的代码生成器配置文件(如下图),jdbc.properties是数据库连接配置文件, mybatis-config.xml是MyBatis核心配置文件,该文件配置了MyBatis的一些全局信息,包含数据库连接信息和Mybatis运行时所需的各种特性,以及设置和影响Mybatis行为的一些属性。 web项目启动时,读取web.xml配置文件,首先解析的是applicationContext.xml文件,其次才是spingmvc.xml文件,spingmvc.xml文件中主要的工作是:启动注解、扫描controller包注解;静态资源映射;视图解析(defaultViewResolver);文件上传(multipartResolver);返回消息json配置。
webapp是放置网页相关文件的目录。
二、DTO
dto,我们可以使用代码生成器生成,和下面方法一致。
三、DAO
我们上面介绍项目结构时说过,我们使用了generatorConfig.xml这个配置文件,其对应的mybatis-generator是一款代码生成器,可以帮助我们快速构建DAO层常见的增删查改功能,一般能够满足我们所有要求。
四、Service层
1. AdminService
这个service调用了5个mapper:
@Autowired private AdministratorMapper administratorMapper; @Autowired private GoodsTypeMapper goodsTypeMapper; @Autowired private GoodsMapper goodsMapper; @Autowired private GoodsImagesMapper goodsImagesMapper; @Autowired private GoodsImagesColorMapper goodsImagesColorMapper;
我们重点讲几个典型的,其实都大同小异。
(1) adminLogin
@Override public List<Administrator> adminLogin(String username, String password) { AdministratorExample admin = new AdministratorExample(); admin.createCriteria().andUsernameEqualTo(username).andPasswordEqualTo(password); List<Administrator> administrators = administratorMapper.selectByExample(admin); return administrators; }
在讲这个之前,我们先介绍什么是Criteria,如下图,Criteria包含一个Cretiron的集合,每一个Criteria对象内包含的Cretiron之间是由AND连接的,是逻辑与的关系。
而Criterion是最基本,它是最底层的Where条件,用于字段级的筛选,feild用于指代字段名字。
而对于oredCriteria,Example内有一个成员叫oredCriteria,是Criteria的集合,这个集合中的Criteria是由OR连接的,是逻辑或关系。
这里我们先利用CTO的Example生成一个admin对象,然后利用
admin.createCriteria().andUsernameEqualTo(username).andPasswordEqualTo(password);List<Administrator> administrators = administratorMapper.selectByExample(admin);
可以查询参数在数据库中数据库中有没有。
(2)selectAll
再来看看selectAll:
@Override public List<Goods> selectAll(){ GoodsExample gc = new GoodsExample(); gc.createCriteria(); return goodsMapper.selectByExample(gc); }
这个操作是查询所有的商品,其对应的sql语句可以这样看待:
select *from Goods//因为createCriteria()之后没有and和or,所以没有where条件为空。
(3)deleteGoodsInfo
@Override public void deleteGoodsInfo(int goodsId){ goodsMapper.deleteByPrimaryKey(goodsId); GoodsImagesColorExample gc = new GoodsImagesColorExample(); gc.createCriteria().andGoodsIdEqualTo(goodsId); goodsImagesColorMapper.deleteByExample(gc); GoodsImagesExample gc1 = new GoodsImagesExample(); gc1.createCriteria().andGoodsIdEqualTo(goodsId); goodsImagesMapper.deleteByExample(gc1); }
因为我们图片和商品数据不在一个表中,所以我们删除商品,需要操作3个表,这里通过主键id在goods表中删除了一条,然后在GoodsImagesColor表中,删除了where条件goodsId为该函数参数的数据,同理,也删除了GoodsImages中的数据。
(4)searchGoodsWithName
@Override public List<Goods> searchGoodsWithName(String name) { // 构建条件 GoodsExample ge = new GoodsExample(); ge.createCriteria().andNameLike("%" + name + "%"); return goodsMapper.selectByExample(ge); }
这里我们使用了一个方法名中带有Like的方法,其作用如下: 实现mysql的like模糊查询一样的操作。这里需要自己拼接%或_。 这段代码用sql语句来描述是这样的:
select * from goods where name like ?
2.GoodsShippingServiceImpl
其实这里面和前面用到的知识都大同小异,不过出现了一个新的面孔。
@Overridepublic List<Goods> findGoodsWithToptype(GoodsType goodstype) { // 根据一级类型查询所有所属二级类型 List<GoodsType> gt = goodsTypeServiceImpl.findSecondLevel(goodstype); // 查询所有二级类型下的所有商品 List<Goods> goodsList = new ArrayList<>(); for (GoodsType goodsType : gt) { List<Goods> goodses = this.findGoodsWithType(goodsType); goodsList.addAll(goodses); } return goodsList;}
该操作是查询某一级目录下的所有二级目录的商品。此处调用了别处的Service。
3.GoodsTypeServiceImpl
(1) findTopLevel
此处多了个IsNull的方法。
@Override public List<GoodsType> findTopLevel() { GoodsTypeExample gte = new GoodsTypeExample(); gte.createCriteria().andPidIsNull(); return goodsTypeMapper.selectByExample(gte); }
这段Java代码可以对应的sql语句为:
@Override public List<Administrator> adminLogin(String username, String password) { AdministratorExample admin = new AdministratorExample(); admin.createCriteria().andUsernameEqualTo(username).andPasswordEqualTo(password); List<Administrator> administrators = administratorMapper.selectByExample(admin); return administrators; }0
即查找pid为空的目录,因为一级目录和二级目录放在一个表中,这样就可以快速查找一级目录了。
4.UserServiceImpl
(1)insetorder
@Override public List<Administrator> adminLogin(String username, String password) { AdministratorExample admin = new AdministratorExample(); admin.createCriteria().andUsernameEqualTo(username).andPasswordEqualTo(password); List<Administrator> administrators = administratorMapper.selectByExample(admin); return administrators; }1
这里我们得了解insert和insertSelective的区别: 如果选择insert 那么所有的字段都会添加一遍,即使有的字段没有值,但是如果使用inserSelective会只给有值的字段赋值(会对传进来的值做非空判断)。
(2)updataorder
@Override public List<Administrator> adminLogin(String username, String password) { AdministratorExample admin = new AdministratorExample(); admin.createCriteria().andUsernameEqualTo(username).andPasswordEqualTo(password); List<Administrator> administrators = administratorMapper.selectByExample(admin); return administrators; }2
record对象则是我们需要修改的数据,example则是我们需要修改的对象 此处代表id为参数id的数据要被修改为参数goodsOrder。
5. UtilServiceImpl
(1)queryByPage
@Override public List<Administrator> adminLogin(String username, String password) { AdministratorExample admin = new AdministratorExample(); admin.createCriteria().andUsernameEqualTo(username).andPasswordEqualTo(password); List<Administrator> administrators = administratorMapper.selectByExample(admin); return administrators; }3
这个util是利用PageHelper进行分页操作。
五、Controller层
这部分应该大家都能看懂,我挑几个重点的讲述一下。
1. adminController
(1)login
@Override public List<Administrator> adminLogin(String username, String password) { AdministratorExample admin = new AdministratorExample(); admin.createCriteria().andUsernameEqualTo(username).andPasswordEqualTo(password); List<Administrator> administrators = administratorMapper.selectByExample(admin); return administrators; }4
这个是后台的登录逻辑,首先是判断用户名或密码是否为空,然后讲密码使用md5算法进行转换,然后传参到adminService的adminLogin,如果有对象返回,就存一个session,返回一个ResponseMessage。否则返回处理失败的ResponseMessage。
(2)searchGoods
@Override public List<Administrator> adminLogin(String username, String password) { AdministratorExample admin = new AdministratorExample(); admin.createCriteria().andUsernameEqualTo(username).andPasswordEqualTo(password); List<Administrator> administrators = administratorMapper.selectByExample(admin); return administrators; }5
这个方法是用于后台Good List查询商品的。
此处根据search_field是id还是name来使用两种方法查询 keyword是在text input标签输入的内容。 然后进行查询分页展示。
2. IndexController
(1)userAddress
@Override public List<Administrator> adminLogin(String username, String password) { AdministratorExample admin = new AdministratorExample(); admin.createCriteria().andUsernameEqualTo(username).andPasswordEqualTo(password); List<Administrator> administrators = administratorMapper.selectByExample(admin); return administrators; }6
此处用到了ModelAndView对象,这个是关键。 他能够将View与Model捆绑在一起。 这个操作是访问收货地址,如果session中没有记录,就前往登录界面。 否则,根据用户ID,在数据库中查找地址信息,然后与视图捆绑渲染。
其他controller的其他方法都大同小异~
六、与前端整合
这里主要使用了Thymeleaf和Ajax,Thymleaf主要是在每个需要后台传数据的标签前面加th:
. 变量用${obj.id}
类似的形式。
下面是文档:
Documentation - Thymeleaf https://www.thymeleaf.org/documentation.html
至于Ajax,本项目主要是类似于下面这样的形式:
@Override public List<Administrator> adminLogin(String username, String password) { AdministratorExample admin = new AdministratorExample(); admin.createCriteria().andUsernameEqualTo(username).andPasswordEqualTo(password); List<Administrator> administrators = administratorMapper.selectByExample(admin); return administrators; }7
其中,url: "/initIndex"
是将要触发传递的路径,method: "GET"
代表POST还是GET或其他方法,success:
代表如果请求成功将要进行的逻辑,error:
代表请求失败要进行的逻辑。
七、后语
这里是R君,代码不止,掘金不停。快来Regan Yue的掘金主页点个关注吧。
原文:https://juejin.cn/post/7098140151515185165