1、Spring和Spring MVC父子容器
概念介绍
1.在Spring与SpringMVC进行整合的时候,一般情况下我们会使用不同的配置文件来配置Spring和SpringMVC,因此我们的应用中会存在至少2个ApplicationContext的实例,由于是在Web应用中,因此最终实例化的是ApplicationContext的子接口 WebApplicationContext。
2.ServletWebApplicationContextRoot WebApplicationContext其中:
- Servlet WebApplicationContext:这是对12E三层架构中的web层进行配置,如控制器(controller),视图解析器(view resolvers)等相关的bean。通过springmvc中提供的DispatchServlet来加载配置,通常情况下,配置文件的名称为springmvc.xml。
- Root WebApplicationConte:这是对J2EE三层架构中的service层、dao层进行配置,如业务bean,数据源(DataSource)等。通常情况下,配置文件的名称为applicationContext.xml。在web应用中,其一般通过ContextLoaderListener来加载。
<?xm1 version="1.0"encoding="uTF-8"?>
<web-appversion="2.4"
xm1ns="http://java.sun.com/xm1/ns/j2ee"
xm1ns:xsi=“http://www.w3.ora/2001/XMLschema-instance"
xs1:schemaLocation="http://iava.sun.com/xm1/ns/i2eehttp://iava.sun.com/xm1/ns/i2ee/web
app_2_4.xsd">
3.同时通过两个容器同时来管理所有的类
会在两个父子IOC容器中生成大量的相同bean,这就会造成内存资源的浪费。
一般正常的操作:
@RequestMapping一般会和@Controller搭配使用。为了防止重复注册bean,建议在springMVC.xml配置文件中只扫描含有Controller bean的包,其它的共用bean的注册定义到applicationContext.xml文件中。
applicationContext.xml
<!--扫播的是com.hp包,但是不扫描contro1ler的注解。--><context:component-scan base-package=com.hp">
<context:exc1ude-filter type="annotation”expression="org.springframework.stereotype.contro1ler"/></contextcomponent-scan>
springMVC.xml
<!--扫描的是com.hp包,但是只扫描contro1ler的注解。-->
<context:component-scan base-package="com.hp”use-default-filters="false">
<context:inc1ude-filter type="annotation”expression="org.springframework.stereotypeContro1ler"/></context:component-scan>
2、项目实例
辅助编程:Navicat、phpstudy_pro、IDEA2020.2.2、TomCat
技术框架:MySQL8.0、Spring、SpringMVC、MyBatis
1.项目架构和相关jar包;
2.创建t_user和goods表
drop database if exists mydb;
create database mydb;
use mydb;
#创建表
create table t_user (
uid int(11) primary key not null AUTO_INCREMENT,
username varchar(20),
password varchar(20),
birthday varchar(20),
phone varchar(11),
address varchar(50)
);
#插入数据
insert into t_user values (1, '张三','111','2022-05-03', '13865430001', '北京');
insert into t_user values (2, '李四','222','2022-05-19', '13598765002', '广州');
insert into t_user values (3, '小红','333','2022-05-19', '15964598003', '郑州');
insert into t_user values (4, '小美','444','2022-05-20', '15765482006', '郑州');
select * from t_user;
#判断删除
drop table if exists goods;
#创建商品信息表
create table goods(
gid int primary key auto_increment,
gname varchar(20),
price double,
stock int,
supplier varchar(50)
);
#插入数据
insert into goods values(1,'泡面',3.5,50,'康师傅');
insert into goods values(2,'牛奶',5.5,60,'蒙牛');
insert into goods values(3,'瓜子',6.5,30,'金鸽');
select * from goods;
3.,创建Module命名为ssm01,成为Web项目,并部署到tomcat服务器中测试项目是否能够正常加载并访问首页
bean包中的实体类分别根据数据库的表名和表的字段名创建,alt+insert快捷键增加setter和getter方法以及toString方法;
注意:属性名全部小写,int和double类型使用封装类Integer和Double,private修饰符修饰
4.创建SSM框架对应的配置文件,三层架构Controller、service、dao
springmvc.xml配置
扫描 controller ; 配置视图解析器; 静态资源不拦截; 开启注解驱动支持(自动配置映射器和适配器);
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!--1.扫描控制器,把控制器对象交给springMVC的IOC统一管理-->
<context:component-scan base-package="com.zhan.controller"/>
<!--2.配置视图解析器-->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!--3.静态资源不拦截-->
<mvc:resources mapping="/css/**" location="/css/"/>
<mvc:resources mapping="/js/**" location="/js/"/>
<mvc:resources mapping="/fonts/**" location="/fonts/" />
<mvc:resources mapping="/img/**" location="/img/"/>
<!--配置拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean id="myInterceptor" class="com.zhan.interceptor.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
<!--4.开启注解驱动支持:默认配置 映射器 和 适配器-->
<mvc:annotation-driven/>
</beans>
spring.xml配置
管理除了 controller 外所有的类; 配置数据源(数据库连接参数); 配置SqlSessionFactoryBean,自动获得数据库连接并得到代理对象; 配置扫描器,告诉 mybatis 要创建哪些接口的代理对象;
<?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:aop="http://www.springframework.org/schema/aop"
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.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--1.让spring框架管理com.chen包中所有的对象,但是排除使用了Controller注解的类-->
<context:component-scan base-package="com.zhan">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!--2.让sprin框架的jdbc管理数据库的连接-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mydb"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<!--3.配置SqlSessionFactoryBean,把SqlSessionFactory对象交给IOC管理,他会自动创建
sqlSession对象,会根据mapper接口再创建代理对象-->
<bean id="factoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:mybatis.xml"/>
</bean>
<!--4.配置扫描器,扫描mapper文件,让mybatis知道要创建什么接口的实现类-->
<bean id="scannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.zhan.dao"/>
</bean>
</beans>
mybatis.xml配置
自身的一些配置,当前阶段为空
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- <settings>-->
<!-- <setting name="logImpl" value="log4j"/>-->
<!-- </settings>-->
</configuration>
配置web项目的核心配置文件web.xml
1. 配置监听器,检测 servlet 容器创建的时候加载 spring.xml 配置文件 ;2. 配置核心控制器 DispatcherServlet ,创建的时候加载 springmvc.xml 配置文件;3. 配置字符集过滤器,设置中文编码;
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!--1.配置监听器,检测servlet容器创建的时候加载 spring.xml-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring.xml</param-value>
</context-param>
<!--2.配置核心控制器DispatcherServlet,创建的时候加载 springmvc.xml-->
<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:springmvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--3.配置字符集过滤器,设置中文编码-->
<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>
</web-app>
5.登录页面的实现
index.jsp首页点击超链接去到登录页
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>首页</title>
</head>
<body>
<h2>欢迎来到项目首页!</h2>
<h3><a href="login.jsp">去登录</a></h3>
</body>
</html>
login.jsp页面输入用户名和密码,正确跳转到主页,错误跳转到错误页;
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登录页</title>
</head>
<body>
<h2>登录页</h2>
<form action="login" method="post">
帐号:<input type="text" name="username" value="" /> <br/>
密码:<input type="password" name="password" value="" /> <br/>
<input type="submit" value="登录" /> <br/>
</form>
</body>
</html>
zhuye.jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>项目主页</title>
</head>
<h2>欢迎${user.username}来到主页</h2>
<h3><a href="addGoods.jsp">添加商品</a></h3>
<body>
<table>
<thead>
<tr>
<th>编号</th>
<th>商品</th>
<th>价格</th>
<th>库存</th>
<th>品牌</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<c:forEach items="${goodsList}" var="goods">
<tr>
<td>${goods.gid}</td>
<td>${goods.gname}</td>
<td>${goods.price}</td>
<td>${goods.stock}</td>
<td>${goods.supplier}</td>
<td>
<a href="delGoods?gid=${goods.gid}">删除</a>
<a href="findByGid?gid=${goods.gid}">修改</a>
</td>
</tr>
</c:forEach>
</tbody>
</table>
</body>
</html>
请求发生后,自动进行数据绑定,拿到用户提交的用户名和密码执行数据的查询,获得数据中该用户的信息;如果信息为空说明登录失败;否则表示登录成功;然后请求查询所有的商品信息;
@Controller
@SessionAttributes({"user"})
public class UserController {
@Autowired
UserService userService;
@RequestMapping("/login")
public ModelAndView login(User user){
//System.out.println("UserController......login");
ModelAndView mv = new ModelAndView();
User login = userService.login(user);
System.out.println(login);
if(login!=null){
mv.addObject("user",login);
mv.setViewName("redirect:/findAll");
}else{
mv.addObject("error","用户名或密码错误!");
mv.setViewName("error");
}
return mv;
}
}
业务层
public interface UserService {
User login(User user);
}
@Service
public class UserServiceImpl implements UserService {
@Autowired
UserDao userDao;
@Override
public User login(User user) {
return userDao.selectForLogin(user);
}
}
持久层
@Repository
public interface UserDao {
@Select("select * from t_user where username=#{username} and password=#{password}")
User selectForLogin(User user);
}
2.实现商品信息的增删改查
增:当点击保存的时候请求 saveGoods ,且传递表单录入的数据,控制器对应的请求处理方法获得商品信息执行数据库的添加操作;
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>添加页</title>
</head>
<body>
<h2>商品信息添加</h2>
<form action="saveGoods" method="post">
商品:<input type="text" name="goodsName" value="" /> <br/>
价格:<input type="number" step="0.01" name="price" value="" /> <br/>
库存:<input type="number" name="stock" value="" /> <br/>
供货商:<input type="text" name="supplier" value="" /> <br/>
<input type="submit" value="保存" /> <br/>
</form>
</body>
</html>
showGoods.jsp修改页面;使用EL表达式把数据显示在表单元素中;由于修改时需要根据id进行修改,所以在数据展示页面的表单中需要显式id且设置为只读状态;
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>修改页</title>
</head>
<body>
<h2>商品信息修改</h2>
<form class="form-horizontal" action="updateGoods" method="post">
编号:<input type="text" name="goodsId" value="${goods.goodsId}" readonly="readonly"> <br/>
商品:<input type="text" name="goodsName" value="${goods.goodsName}"><br/>
价格:<input type="number" step="0.01" name="price" value="${goods.price}"> <br/>
库存:<input type="number" name="stock" value="${goods.stock}"> <br/>
供货商:<input type="text" name="supplier" value="${goods.supplier}"><br/>
<input type="submit" value="修改">
</form>
</body>
</html>
控制层
package com.zhan.controller;
import com.zhan.bean.Goods;
import com.zhan.service.GoodsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.servlet.ModelAndView;
import java.util.List;
@Controller
@SessionAttributes({"goodsList"})
public class GoodsController {
@Autowired
GoodsService goodsService;
@RequestMapping("/findAll")
public ModelAndView findAll(){
ModelAndView mv=new ModelAndView();
List<Goods> goodsList = goodsService.findAll();
mv.addObject("goodsList",goodsList);
mv.setViewName("zhuye");
return mv;
}
@RequestMapping("/delGoods")
public ModelAndView delGoods(int gid){
ModelAndView mv=new ModelAndView();
int n = goodsService.delGoods(gid);
if(n>0){
//继续查询数据,跳转主页
mv.setViewName("redirect:/findAll");
} else{
mv.addObject("error","删除出错了!");
mv.setViewName("error"); //经过视图解析器,去指定位置 找到指定后缀的页面
}
return mv;
}
@RequestMapping("/addGoods")
public ModelAndView addGoods(Goods goods){
ModelAndView mv=new ModelAndView();
int n = goodsService.addGoods(goods);
if(n>0){
//重新获取一次最新的数据,跳转到主页
mv.setViewName("redirect:/findAll");
} else{
mv.addObject("error","添加出错了!");
mv.setViewName("error");
}
return mv;
}
@RequestMapping("/findById")
public ModelAndView findById(int gid){
ModelAndView mv=new ModelAndView();
Goods goods = goodsService.findById(gid);
//把数据发送到页面中做展示---数据回显
mv.addObject("goods",goods); //request域
mv.setViewName("showGoods"); //请求转发
return mv;
}
@RequestMapping("/updateGoods")
public ModelAndView updateGoods(Goods goods){
ModelAndView mv=new ModelAndView();
int n = goodsService.updateGoods(goods);
if(n>0){
//重新获取一次最新的数据,跳转到主页
mv.setViewName("redirect:/findAll");
} else{
mv.addObject("error","修改出错了!");
mv.setViewName("error");
}
return mv;
}
@RequestMapping("/seach")
public ModelAndView seach(String gname){
ModelAndView mv=new ModelAndView();
List<Goods> goodsList = goodsService.findByGname(gname);
mv.addObject("goodsList",goodsList);
mv.setViewName("zhuye");
return mv;
}
}
业务层
public interface GoodsService {
List<Goods> findAll();
Goods findById(int gid);
List<Goods> findByGname(String gname);
int delGoods(int gid);
int addGoods(Goods goods);
int updateGoods(Goods goods);
}
package com.zhan.service.impl;
import com.zhan.bean.Goods;
import com.zhan.dao.GoodsDao;
import com.zhan.service.GoodsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class GoodsServiceImpl implements GoodsService {
@Autowired
GoodsDao goodsDao;
@Override
public List<Goods> findAll() {
return goodsDao.selectAll();
}
@Override
public Goods findById(int gid) {
return goodsDao.selectById(gid);
}
@Override
public List<Goods> findByGname(String gname) {
return goodsDao.selectByGname(gname);
}
@Override
public int delGoods(int gid) {
return goodsDao.delete(gid);
}
@Override
public int addGoods(Goods goods) {
return goodsDao.insert(goods);
}
@Override
public int updateGoods(Goods goods) {
return goodsDao.update(goods);
}
}
持久层
package com.zhan.dao;
import com.zhan.bean.Goods;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import java.util.List;
public interface GoodsDao {
@Select("select * from goods")
List<Goods> selectAll();
@Select("select * from goods where gid=#{gid}")
Goods selectById(int gid);
@Select("select * from goods where gname like concat('%',#{gname},'%')")
List<Goods> selectByGname(String gname);
@Delete("delete from goods where gid=#{gid}")
int delete(int gid);
@Insert("insert into goods(gname,price,stock,supplier) values(#{gname},#{price},#{stock},#{supplier})")
int insert(Goods goods);
@Update("update goods set gname=#{gname} , price=#{price} ,stock=#{stock} ,supplier=#{supplier} where gid=#{gid}")
int update(Goods goods);
}
登录拦截
判断是否为登录请求,是的话放行,否则继续判断session中是否用用户信息,有表示已登录放行,没有则拦截并强制跳转到登录页
public class MyInterceptor implements HandlerInterceptor{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String path = request.getServletPath();
//判断是否为登录请求,是的话放行,否则继续判断session中是否用用户信息,有表示已登录放行,没有则拦截并强制跳转到登录页
if (path.equals("/login")) {
return true;
} else {
User user = (User) request.getSession().getAttribute("user");
if (user != null) {
return true;
} else {
response.sendRedirect("login.jsp");
return false;
}
}
}
}