Spring练习
1 Spring环境搭建步骤
①创建工程
②导入静态页面
③导入需要坐标
④创建包结构
⑤导入数据库脚本
⑥创建POJO类
⑦创建配置文件
对于⑦重点说明:
配置文件主要是对applicationContext和spring-mvc以及web.xml进行配置。
web.xml:
1)配置Spring监听器
1 2 3 4 5 6 7 8 9 10 | <!-- 全局的初始化参数 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <!-- Spring监听器 --> <listener> <listener- class >org.springframework.web.context.ContextLoaderListener</listener- class > </listener> |
作用:ContextLoaderListener会读取这些XML文件并产生 WebApplicationContext对象,然后将这个对象放置在ServletContext的属性
里,这样我们只要可以得到Servlet就可以得到WebApplicationContext对象,并利用这个对象访问spring 容器管理的bean。
2)配置Spring-mvc的前端控制器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <!-- Spring-mvc的前端控制器 --> <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> <load-on-startup> 1 </load-on-startup> </servlet> <servlet-mapping> <servlet-name>DispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> |
所有请求地址都将经过这个servlet,且优先度为1,由spring-mvc来完成地址的映射和类的注入
关于初始化参数contextConfigLocation的含义,在Spring MVC的学习笔记中有提到。
spring-mvc.xml:
1)mvc注解驱动
1 2 | <!-- mvc注解驱动 --> <mvc:annotation-driven/> |
在业务方法返回对象时,会自动将该对象转换成json格式的字符串
2)视图解析器
1 2 3 4 5 | <!-- 配置视图解析器 --> <bean class = "org.springframework.web.servlet.view.InternalResourceViewResolver" > <property name= "prefix" value= "/pages/" /> <property name= "suffix" value= ".jsp" /> </bean> |
在进行页面跳转时,会自动拼接prefix+xxx+suffix。
3)静态资源开放
1 2 | <!-- 静态资源开放 如果不开放相关的资源,那么所有的地址请求都将通过Dispatcher适配器找RequestMapping映射,有的资源就无法找到 --> <mvc: default -servlet-handler/> |
在访问非响应体请求时使用默认的适配器。
4)组件扫描
1 2 | <!-- 组件扫描 扫描Controller --> <context:component-scan base- package = "com.xc.controller" /> |
applicationContext.xml:
1)加载分离出的数据库配置属性
1 2 | <!-- 加载jdbc.properties资源 --> <context:property-placeholder location= "classpath:jdbc.properties" /> |
2)配置数据源对象
1 2 3 4 5 6 7 | <!-- 配置数据源对象 --> <bean id= "dataSource" class = "com.mchange.v2.c3p0.ComboPooledDataSource" > <property name= "driverClass" value= "${jdbc.driver}" /> <property name= "jdbcUrl" value= "${jdbc.url}" /> <property name= "user" value= "${jdbc.username}" /> <property name= "password" value= "${jdbc.password}" /> </bean> |
3)配置JdbcTemplate对象
1 2 3 4 | <!-- 配置JdbcTemplate对象 --> <bean id= "jdbcTemplate" class = "org.springframework.jdbc.core.JdbcTemplate" > <property name= "dataSource" ref= "dataSource" /> </bean> |
4)配置Service层+Dao层的对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <!-- 配置Service对象 --> <bean id= "roleService" class = "com.xc.service.impl.RoleServiceImpl" > <property name= "roleDao" ref= "roleDao" /> </bean> <!-- 配置Dao对象 --> <bean id= "roleDao" class = "com.xc.dao.impl.RoleDaoImpl" > <property name= "jdbcTemplate" ref= "jdbcTemplate" /> </bean> <bean id= "userService" class = "com.xc.service.impl.UserServiceImpl" > <property name= "userDao" ref= "userDao" /> <property name= "roleDao" ref= "roleDao" /> </bean> <bean id= "userDao" class = "com.xc.dao.impl.UserDaoImpl" > <property name= "jdbcTemplate" ref= "jdbcTemplate" /> </bean> |
web层使用注解的方式配置映射和注入相应的Service类,而Service层和Dao层对象则是通过ApplicationContext.xml配置。
2. 角色列表的展示步骤分析
1)点击角色管理菜单发送请求到服务器端
1 2 3 | < li >< a href="${pageContext.request.contextPath}/role/list"> < br > < i class="fa fa-circle-o"></ i > 角色管理 </ a ></ li > |
该请求会通过MVC,扫描Controller下的/role/list,执行对应的业务方法。
然后由该业务方法返回的ViewName来显示页面,该业务方法返回的Model来返回要显示的数据。
2)创建RoleController和showList()方法
1 2 3 4 5 6 7 8 9 10 | @RequestMapping ( "/list" ) public ModelAndView list(){ ModelAndView modelAndView = new ModelAndView(); List<Role> roleList = roleService.list(); //设置模型 modelAndView.addObject( "roleList" ,roleList); //设置视图 modelAndView.setViewName( "role-list" ); return modelAndView; } |
RoleController层都是/role子目录下的业务方法,该业务方法是/list。
该方法既要回传参数,又要跳转界面,所以返回ModelAndView对象。
该业务方法调用了roleService对象的list方法,所以要在类中配置一个RoleService服务类,并用注解自动注入,
由于类中仅有且仅会一个RoleService类,所以只用加注解@AutoWired。
1 2 | @Autowired private RoleService roleService; |
3)创建RoleService和showList()方法
到了Service层以及Dao层之后,一般采用接口+实现类的模式。
采用接口的原因,是为了让上层类不依赖于下层类。
如果下层类内部改变的话,不必修改上层类,这对更新和维护提供了方便。
还有一个我觉得方便的点,别的层的开发人员只需要对接口方法的注释进行查看,不用考虑方法的具体实现,可以直接拿来使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | public class RoleServiceImpl implements RoleService { private RoleDao roleDao; public void setRoleDao(RoleDao roleDao) { this .roleDao = roleDao; } public List<Role> list() { List<Role> roleList = roleDao.findAll(); return roleList; } } |
这个服务方法构成简单,只要接收Dao层对角色的查询结果,所以仅仅在方法内调用了Dao层的findAll方法。
因为该类的配置已经在xml中配置,所以不需要加注解配置。
4)创建RoleDao和findAll()方法
接口和实现类的配置类似3)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | public class RoleDaoImpl implements RoleDao { private JdbcTemplate jdbcTemplate; public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { this .jdbcTemplate = jdbcTemplate; } public List<Role> findAll() { List<Role> roleList = jdbcTemplate.query( "select * from sys_role" , new BeanPropertyRowMapper<Role>(Role. class )); return roleList; } } |
Dao层采用JDbc模板对数据库进行访问,方法中调用了query方法,通过映射注入Role实体类中然后放入集合,并以List<Role>接收。
具体用法在JdbcTemplate中已有说明。
5)使用JdbcTemplate完成查询操作
在4)中已有体现。
6)将查询数据存储到Model中
在2)中已有体现。
7)转发到role-list.jsp页面进行展示
在2)中已有体现。
3. 角色添加的步骤分析
1)点击列表页面新建按钮跳转到角色添加页面
1 2 3 | <button type= "button" class = "btn btn-default" title= "新建" onclick= "location.href='${pageContext.request.contextPath}/pages/role-add.jsp'" > <i class = "fa fa-file-o" ></i> 新建 </button> |
通过location.href进行页面跳转。
2)输入角色信息,点击保存按钮,表单数据提交服务器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | <form action= "${pageContext.request.contextPath}/role/save" method= "post" > <!-- 正文区域 --> <section class = "content" > <!--产品信息--> <div class = "panel panel-default" > <div class = "panel-heading" >角色信息</div> <div class = "row data-type" > <div class = "col-md-2 title" >角色名称</div> <div class = "col-md-4 data" > <input type= "text" class = "form-control" name= "roleName" placeholder= "角色名称" value= "" > </div> <div class = "col-md-2 title" >角色描述</div> <div class = "col-md-4 data" > <input type= "text" class = "form-control" name= "roleDesc" placeholder= "角色描述" value= "" > </div> </div> </div> <!--订单信息/--> <!--工具栏--> <div class = "box-tools text-center" > <button type= "submit" class = "btn bg-maroon" >保存</button> <button type= "button" class = "btn bg-default" onclick= "history.back(-1);" >返回</button> </div> <!--工具栏/--> </section> <!-- 正文区域 /--><br></form> |
form表单以post形式提交至/role/save业务方法上,通过回传相应参数,有roleName,roleDesc。
3)编写RoleController的save()方法
类似之前业务的方法,映射一个/save地址。
1 2 3 4 5 | @RequestMapping ( "/save" ) public String save(Role role){ roleService.save(role); return "redirect:/role/list" ; } |
此时的参数为实体类Role,类中的属性要与表单中的name属性一致,这样mvc才会将相应的属性一一对应注入。
返回必须是重定向的获取list的请求地址,如果跳过此步直接返回显示页面,页面中的数据会是空的。
4)编写RoleService的save()方法
1 2 3 | public void save(Role role) { roleDao.save(role); } |
5)编写RoleDao的save()方法
1 2 3 4 | public void save(Role role) { jdbcTemplate.update( "insert into sys_role values(?,?,?)" , null ,role.getRoleName(),role.getRoleDesc()); } |
6)使用JdbcTemplate保存Role数据到sys_role
已经在5)中有体现。
7)跳转返回角色列表页面
4.用户增加的步骤分析
步骤大体上与角色添加类似,但是有地方需要说明。
因为在添加用户的同时,需要指定用户的角色,而角色列表需要通过前端向后端请求获得,
并且添加用户的信息需要分成2部分保存。
1)用户本身的信息存放在sys_user表。
2)用户的角色信息存放在sys_user_role表。
此处有一个知识点,用户本身可以拥有多个角色身份,而一个角色身份也可以对应多个用户。
所以仅仅是用户表和角色表2个表并不能完全的符合这两者之间的关系。
一般这种多对多的关系需要第三张表,称为中间表。
本例中的中间表分为2列,一列是userId,代表用户的id,一列是roleId,代表角色的id。
每一条信息代表着,用户对应着某一角色。
例如上图,用户1有2个角色,一个是角色1,一个是角色2。
4.1 加载添加用户的界面
controller层
1 2 3 4 5 6 7 8 | @RequestMapping ( "/saveUI" ) public ModelAndView saveUI(){ ModelAndView modelAndView = new ModelAndView(); List<Role> roleList = roleService.list(); modelAndView.addObject( "roleList" ,roleList); modelAndView.setViewName( "user-add" ); return modelAndView; } |
查询角色的功能之前已经写过,所以直接复用就行,也是非常的方便。
其他层也是类似,不多赘述。
4.2 添加用户的功能
controller层
1 2 3 4 5 | @RequestMapping ( "/save" ) public String save(User user,Long[] roleIds){ userService.save(user,roleIds); return "redirect:/user/list" ; } |
上文说到需要将信息分为2部分保存,参数User用来保存sys_user表的信息,roleIds数据用来保存sys_user_role表的信息。
Service层
1 2 3 4 5 6 | public void save(User user, Long[] roleIds) { //第一步 向sys_user 表中存储数据 long userId = userDao.save(user); //第二步 向sys_user_role 关系表中存储多条数据 userDao.saveUserRoleRel(userId,roleIds); } |
Dao层
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | public long save( final User user) { //创建PreparedStatementCreator PreparedStatementCreator creator = new PreparedStatementCreator() { public PreparedStatement createPreparedStatement(Connection con) throws SQLException { //使用原始jdbc完成一个PreparedStatement的组建 PreparedStatement preparedStatement = con.prepareStatement( "insert into sys_user values(?,?,?,?,?)" , PreparedStatement.RETURN_GENERATED_KEYS); preparedStatement.setObject( 1 , null ); preparedStatement.setString( 2 ,user.getUsername()); preparedStatement.setString( 3 ,user.getEmail()); preparedStatement.setString( 4 ,user.getPassword()); preparedStatement.setString( 5 ,user.getPhoneNum()); return preparedStatement; } }; //创建keyHolder GeneratedKeyHolder keyHolder = new GeneratedKeyHolder(); jdbcTemplate.update(creator,keyHolder); long userId = keyHolder.getKey().longValue(); //jdbcTemplate.update("insert into sys_user values(?,?,?,?,?)",null,user.getUsername(),user.getEmail(),user.getPassword(),user.getPhoneNum()); return userId; } |
这边有一点需要说明,如果将update函数用sql语句来实现的话,传入的参数应该是user.getId(),但user中的id并不是前端传到后端去的,而是数据库表自增的id,所以并没有存放在实体类中。
jdbc有一个方法可以返回这个id值,第一个参数为PreparedStatementCreator对象,第二个为keyHolder对象,因为不常用加上现在有更好用的mybatis,所以只做练习,试一遍就好。
5 删除用户的功能
删除用户需要注意的点是,需要在请求地址上携带需要删除的用户id。
之前在进行列表展示的时候已经获取了用户的id,而且删除的按钮在同一循环里,所以要获取用户的id也非常的容易。
controller层
1 2 3 4 5 | @RequestMapping ( "/del/{userId}" ) public String del( @PathVariable ( "userId" ) Long userId){ userService.del(userId); return "redirect:/user/list" ; } |
参数上的注解之前的文章也有说过,是获取请求地址中的变量。
Service层
1 2 3 4 5 6 | public void del(Long userId) { //1、删除sys_user_role关系表 userDao.delUserRoleRel(userId); //2、删除sys_user表 userDao.del(userId); } |
删除同样分为2部分进行删除,一个是删除从属表用户角色表,另一个是删除主表角色表。
Dao层
1 2 3 4 5 6 7 | public void delUserRoleRel(Long userId) { jdbcTemplate.update( "delete from sys_user_role where userId=?" ,userId); } public void del(Long userId) { jdbcTemplate.update( "delete from sys_user where id=?" ,userId); } |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· NetPad:一个.NET开源、跨平台的C#编辑器
· 面试官:你是如何进行SQL调优的?