文章目录
SSM案例整合
前言:Spring和SpringMVC整合注意事项
避免容器重复创建
在各自的XML文件中只搜寻属于自己分工的注解创建容器
spring.xml:
<context:component-scan base-package="com.atguigu">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<context:exclude-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
</context:component-scan>
spingMVC.xml
<context:component-scan base-package="com.atguigu">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<context:exclude-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
</context:component-scan>
避免父类自动注入子类容器
众所周知,在spring和springMVC在创建容器中默认会使spring成为父容器,而springMVC为子容器
环境搭建
1.创建maven的webapp工程
2.补全maven-web工程的目录结构
3.导入相关三个框架以及要实现功能所需的jar
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.3</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.24</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.3</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.22</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.3.3</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.3.3</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.3</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.3.3</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.3</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.3.3</version>
</dependency>
<dependency>
<groupId>org.apache.taglibs</groupId>
<artifactId>taglibs-standard-impl</artifactId>
<version>1.2.5</version>
</dependency>
<dependency>
<groupId>org.apache.taglibs</groupId>
<artifactId>taglibs-standard-spec</artifactId>
<version>1.2.5</version>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator-annotation-processor</artifactId>
<version>6.1.5.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.1.5.Final</version>
</dependency>
<dependency>
<groupId>com.fasterxml</groupId>
<artifactId>classmate</artifactId>
<version>1.5.1</version>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<version>3.4.1.Final</version>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.12.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.12.1</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
相关jar包的作用可自行百度
4.导入bootstrap的相关组件
bootstrap官网链接
解压导入webapp下static文件中
引入文件和js库标识
5.导入jQuery包
博主直接引用了网站地址,没有下载实体包
6.配置web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<display-name>Archetype Created Web Application</display-name>
<!--启动spring容器-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:application.xml</param-value>
</context-param>
<!--配置SpringMVC的前端控制器,拦截所有请求-->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--一定要配置初始化,来让springMVC.xml扫描全局注解-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springMVC.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>
<!--字符编码过滤器,一定要放在所有过滤器之前-->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<!-- encoding:指定解决POST请求乱码 -->
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<!-- forceEncoding:顺手解决响应乱码;response.setCharacterEncoding(this.encoding); -->
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>forceRequestEncoding</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--使用Rest风格URI的过滤器,将页面中post请求隐性转换成put和delete请求-->
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
7.配置SpringMVC的xml文件
<!--这里名称空间必须有响应的标识,才能用mvc-->
<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:mvc="http://www.springframework.org/schema/mvc"
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/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--开启注解扫描,只扫描控制器-->
<context:component-scan base-package="com.lhjitem" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!--配置拦截器,方便页面返回-->
<!--配置映射(视图)解析器:如何将控制器返回的结果字符串,转换为一个物理的视图文件-->
<bean id="irvr" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--prefix(前缀)是代表跳转页面文件的所在目录-->
<property name="prefix" value="/WEB-INF/views/"></property>
<!--suffix(后缀)表示文件的后缀名-->
<property name="suffix" value=".jsp"></property>
</bean>
<!--两个标准配置-->
<!--将springMVC不能处理的请求交给tomcat-->
<mvc:default-servlet-handler/>
<!--能支持springMVC一些高级的功能,从此走上开挂之路,
例如JSR303校验、快捷的ajax,但归根结底还是为了能使动态资源管用-->
<mvc:annotation-driven></mvc:annotation-driven>
</beans>
8.配置Spring的xml文件
Spring配置文件的核心:
- 数据源
- 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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!--Spring的配置文件,这里主要配置和业务逻辑有关的-->
<!--配置扫描各种组件的context-->
<context:component-scan base-package="com.lhjitem">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!--首先配置数据库连接池和数据源,由jar包可知,博主用的时阿里的druid-->
<!--用context标签引入配置jdbc的properties文件-->
<context:property-placeholder location="classpath:dbconfig.properties"></context:property-placeholder>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.Driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!--配置与Mybatis的整合-->
<bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--指出mybatis全局配置文件的位置-->
<property name="configLocation" value="mybatis-config.xml"></property>
<!--指定数据源,因为前面已经配置好了数据源,所以直接用ref引用即可-->
<property name="dataSource" ref="dataSource"></property>
<!--只用mybatis的mapper文件位置-->
<property name="mapperLocations" value="classpath:mapper/*.xml"></property>
</bean>
<!--配置扫描器,将mybatis接口的实现加入到ioc容器中-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--扫描所有dao接口的实现,加入到ioc容器中-->
<property name="basePackage" value="com.lhjitem.dao"></property>
</bean>
<!--配置事务控制-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--要想事务管理就得控制住数据源-->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--开启基于注解的事务管理,使用xml配置形式的事务(重要的配置都使用配置式)-->
<aop:config>
<!--切入点表达式-->
<aop:pointcut id="txPc" expression="execution(* com.lhjitem.service..*(..))"/>
<!--配置事务增强-->
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPc"></aop:advisor>
</aop:config>
<!--配置事务增强,事务如何切入,事务如何管理-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!--*的意思就是切入的所有方法都是事务方法-->
<tx:method name="*"/>
<!--以get开始的方法-->
<tx:method name="get*" read-only="true"></tx:method>
</tx:attributes>
</tx:advice>
</beans>
9.配置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="mapUnderscoreToCamelCase " value="true"/>
</settings>
<!--配置bean-->
<typeAliases>
<package name="com.lhjitem.pojo"/>
</typeAliases>
</configuration>
10.利用MyBatis Generator反向生成dao、Javabean
- 创建数据库、员工表、部门表
//创建数据库
CREATE DATABASE ssm_item
USE ssm_item
//员工表
CREATE TABLE `emp` (
`emp_id` int NOT NULL AUTO_INCREMENT,
`emp_name` varchar(255) NOT NULL,
`gender` char(1) DEFAULT NULL,
`email` varchar(255) DEFAULT NULL,
`d_id` int DEFAULT NULL,
PRIMARY KEY (`emp_id`),
KEY `fk_emp_dept` (`d_id`),
CONSTRAINT `fk_emp_dept` FOREIGN KEY (`d_id`) REFERENCES `dept` (`dept_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
//部门表
CREATE TABLE `dept` (
`dept_id` int NOT NULL AUTO_INCREMENT,
`dept_name` varchar(255) NOT NULL,
PRIMARY KEY (`dept_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
- 先导入MyBatis Generator的jar包
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.7</version>
</dependency>
- 然后编写MyBatis Generator的配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<context id="DB2Tables" targetRuntime="MyBatis3">
<!--mybatis反向生成dao与javabean对象,取消注解生成-->
<commentGenerator>
<property name="suppressAllComments" value="true"/>
</commentGenerator>
<!--配置数据库链接-->
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/ssm_item"
userId="root"
password="200627">
</jdbcConnection>
<javaTypeResolver >
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>
<!--配置javabean生成的位置-->
<javaModelGenerator targetPackage="com.lhjitem.pojo"
targetProject=".\src\main\java">
<property name="enableSubPackages" value="true" />
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!-- 指定sql映射文件生成的位置-->
<sqlMapGenerator targetPackage="mapper"
targetProject=".\src\main\resources">
<property name="enableSubPackages" value="true" />
</sqlMapGenerator>
<!--指定dao接口生成的位置,mapper接口-->
<javaClientGenerator type="XMLMAPPER"
targetPackage="com.lhjitem.dao"
targetProject=".\src\main\java">
<property name="enableSubPackages" value="true" />
</javaClientGenerator>
<!--table标签指定每个表的生成策略-->
<!--tableName指定数据库中的表名、domainObjectName生成的pojo对象名-->
<table tableName="emp" domainObjectName="Employee"></table>
<table tableName="dept" domainObjectName="Department"></table>
</context>
</generatorConfiguration>
- 编写测试生成类
public class MBGTest {
public static void main(String[] args) throws Exception{
List<String> warnings = new ArrayList<String>();
boolean overwrite = true;
//这个指定MyBatis Generator的配置文件位置
File configFile = new File("D:\\JAVA_Files\\SSM_CRUD\\src\\main\\resources\\mbg.xml");
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(configFile);
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
myBatisGenerator.generate(null);
}
}
11.调整MyBatis Generator反向生成dao、Javabean的结构
先看一下生成的目录结构
- 在EmployeeMapper接口中添加两个查询语句(普通的与根据主键的)
为了查询员工信息的时候带有部门信息
List<Employee> selectByExampleWithDept(EmployeeExample example);
Employee selectByPrimaryKeyWithDept(Integer empId);
- 由于添加的是带有部门信息的查询方法,所以在员工类Employee中要封装部门类
private Department department;
//希望查询员工的同时部门信息也是查询好的
public Department getDepartment() {
return department;
}
public void setDepartment(Department department) {
this.department = department;
}
- 在EmployeeMapper.xml中添加相对应的sql语句
<!--定义自己的返回值类型-->
<resultMap id="WithDeptResultMap" type="com.lhjitem.pojo.Employee">
<id column="emp_id" jdbcType="INTEGER" property="empId" />
<result column="emp_name" jdbcType="VARCHAR" property="empName" />
<result column="gender" jdbcType="CHAR" property="gender" />
<result column="email" jdbcType="VARCHAR" property="email" />
<result column="d_id" jdbcType="INTEGER" property="dId" />
<association property="department" javaType="com.lhjitem.pojo.Department">
<id column="dept_id" property="deptId"/>
<result column="dept_name" property="deptName"/>
</association>
</resultMap>
<!--配置查询带上部门的sql-->
<sql id="WithDept_Column_List">
e.emp_id, e.emp_name, e.gender, e.email, e.d_id, d.dept_id, d.dept_name
</sql>
<!--配置自己写的查询带部门的select语句-->
<select id="selectByExampleWithDept" resultMap="WithDeptResultMap">
select
<if test="distinct">
distinct
</if>
<include refid="WithDept_Column_List" />
from emp e
left join dept d on e.`d_id`=d.`dept_id`
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
<if test="orderByClause != null">
order by ${orderByClause}
</if>
</select>
<!--配置按照主键来查询带部门的select语句-->
<select id="selectByPrimaryKeyWithDept" resultMap="WithDeptResultMap">
select
<include refid="WithDept_Column_List" />
from emp e
left join dept d on e.`d_id`=d.`dept_id`
where emp_id = #{empId,jdbcType=INTEGER}
</select>
12.测试CRUD的操作
我们采用spring整合的spring-test直接来测试
注意:Junit的版本一定要在4.12及以上
如在这里遇到错误请直接跳到结尾看错误信息总结,对症下药
/**
* 测试dao层是否能正常工作
* 这里我们使用spring中的spring-test来测试,让mapper自动注入IOC容器中
*/
@RunWith(SpringJUnit4ClassRunner.class)
/*指定配置文件的位置*/
@ContextConfiguration(locations = "classpath:application.xml")
public class MapperTest {
/*用Autowired注解直接自动注入*/
@Autowired
DepartmentMapper departmentMapper;
@Autowired
EmployeeMapper employeeMapper;
@Autowired
SqlSession sqlSession;
/**
* 插入部门
*/
@Test
public void testAddDept(){
departmentMapper.insertSelective(new Department(null, "男酮部门"));
departmentMapper.insertSelective(new Department(null, "人力资源部"));
departmentMapper.insertSelective(new Department(null, "烟酒生意部"));
departmentMapper.insertSelective(new Department(null, "起飞部门"));
departmentMapper.insertSelective(new Department(null, "JAVA开发部门"));
}
/**
* 测试添加员工
*/
@Test
public void testAddEmp(){
employeeMapper.insertSelective(new Employee(null,"张三","男","abc@qq.com",1));
employeeMapper.insertSelective(new Employee(null,"李四","男","dfg@qq.com",2));
employeeMapper.insertSelective(new Employee(null,"王五","男","hij@qq.com",3));
employeeMapper.insertSelective(new Employee(null,"杨六","女","klm@qq.com",4));
//批量添加,使用可以执行批量操作的sqlSession
EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
for (int i=0; i<2; i++){
String name = UUID.randomUUID().toString().substring(0,5)+ i;
mapper.insertSelective(new Employee(null,name,"女",name+"@163.com",5));
}
}
}
在spring的配置文件中编写批量添加sqlSession对应bean标签
<!--配置一个可以执行批量的sqlSession-->
<bean id="sessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg name="sqlSessionFactory" ref="SessionFactory"></constructor-arg>
<constructor-arg name="executorType" value="BATCH"></constructor-arg>
</bean>
数据库结果:
员工表
部门表
查询各功能的实现
- 访问index.jsp页面
- index.jsp页面发送出查询员工列表请求
- EmployeeController来接收请求,查出员工信息
- 来到list.jsp页面
1.查询员工信息(分页查询)
/**
* 处理员工CRUD操作
*/
@Controller
public class EmployeeController {
@Autowired
EmployeeService employeeService;
/**
* 查询员工信息(分页查询)
* pn是pageNumber
* @return
*/
@RequestMapping("/emps")
public String getEmps(@RequestParam(value = "pn", defaultValue = "1") Integer pn, Model model){
//为了分页查询,我们引入一个PageHelper分页插件
//在查询之前只需要调用startPage,从第几页开始查,每页几个
PageHelper.startPage(pn,5);
List<Employee> employees = employeeService.getAllEmps();
//查询完后pageInfo来包装查询后的结果(封装了详细的分页信息,包括我们查询出来的数据)
// 只需要把这个pageInfo给页面后就不需要在关心什么了
//传入连续显示的页数
PageInfo page = new PageInfo(employees,5);
//放到model中,以便页面使用
model.addAttribute("pageInfo",page);
return "list";
}
}
员工业务层类
@Service
public class EmployeeService {
//调用dao层
@Autowired
EmployeeMapper employeeMapper;
/**
* 查询所有员工
*
* @return
*/
public List<Employee> getAllEmps(){
return employeeMapper.selectByExampleWithDept(null);
}
}
因为我们用到了专门帮助实现分页的各种功能的插件所有需要导包和配置
<!--引入pageHelper的jar包-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.2.0</version>
</dependency>
在mybatis的配置文件中
<!--配置分页插件,plugins有位置要求,写在typeAliases标签后面-->
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>
编写测试类
/**
* 用spring-test测试提供的测试请求功能,测试crud请求的正确性
*/
@RunWith(SpringJUnit4ClassRunner.class)
/*WebAppConfiguration这个注解就是为了配置在spring中没有配置的ioc容器
* WebApplicationContext就是在spring配置文件中没有配置的,所以采用这个方式
* */
@WebAppConfiguration
/*指定配置文件的位置*/
@ContextConfiguration(locations = {"classpath:application.xml", "classpath:springMVC.xml"})
public class MvcTest {
//传入springMVC的ioc容器
@Autowired
WebApplicationContext context;
//虚拟MVC的请求,获取到处理的结果
MockMvc mockMvc;
//初始化创建mockMvc
@Before
public void initMokMvc(){
mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
}
@Test
public void testPage() throws Exception{
//模拟请求拿到返回值
MvcResult result = mockMvc.perform(MockMvcRequestBuilders.get("/emps")
.param("pn", "1")).andReturn();
//请求成功以后,请求域中会有pageInfo,我们可以取出并进行验证
MockHttpServletRequest request = result.getRequest();
PageInfo pageInfo = (PageInfo) request.getAttribute("pageInfo");
System.out.println("当前页码为:"+pageInfo.getPageNum());
System.out.println("总页码:"+pageInfo.getPages());
System.out.println("总记录数:"+pageInfo.getTotal());
System.out.println("在页面需要连续显示的页码");
int[] nums = pageInfo.getNavigatepageNums();
for(int i: nums){
System.out.print(""+i);
}
//获取员工数据,因为我们一并将员工信息包装到了pageInfo
List<Employee> list = pageInfo.getList();
for (Employee employee : list) {
System.out.println();
}
}
}
之前我们添加了6个员工所以结果是正常的:
2.完善列表信息页面的jsp
全程使用bootstrap的组件格式,还是那句话记得引入jQuery
记得配置一个全局路径,以后好引用
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%
//全局路径
pageContext.setAttribute("road",request.getContextPath());
%>
<!-- 加载 Bootstrap 的所有 JavaScript 插件。你也可以根据需要只加载单个插件。 -->
<script src="static/bootstrap-3.4.1-dist/js/bootstrap.js"></script>
<!-- Bootstrap -->
<link rel="stylesheet" href="static/bootstrap-3.4.1-dist/css/bootstrap.css">
<script type="text/javascript" src="js/jquery-3.5.1.js"></script>
<html>
<head>
<title>员工列表</title>
</head>
<body>
<%--搭建显示页面,简单分别四行来显示--%>
<div class="container">
<%--标题--%>
<div class="row">
<div class="col-md-12">
<h1>SSM-ITEM</h1>
</div>
</div>
<%--按钮--%>
<div class="row">
<div class="col-md-4 col-md-offset-8">
<button class="btn btn-primary">新增</button>
<button class="btn btn-danger">删除</button>
</div>
</div>
<%--显示表格信息--%>
<div class="row">
<div class="col-md-12">
<table class="table table-hover">
<tr>
<th>#id</th>
<th>empName</th>
<th>gender</th>
<th>email</th>
<th>department</th>
<th>操作</th>
</tr>
<%--拿出pageInfo中的专门封装对象的list--%>
<c:forEach items="${pageInfo.list}" var="emp">
<tr>
<th>${emp.empId}</th>
<th>${emp.empName}</th>
<th>${emp.gender}</th>
<th>${emp.email}</th>
<th>${emp.department.deptName}</th>
<th>
<button class="btn btn-success btn-sm">
<span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>
编辑
</button>
<button class="btn btn-info btn-sm">
<span class="glyphicon glyphicon-trash" aria-hidden="true"></span>
新增
</button>
</th>
</tr>
</c:forEach>
</table>
</div>
</div>
<%--显示分页信息按钮--%>
<div class="row">
<%--分页文字信息--%>
<div class="col-md-6">
<h4>当前${pageInfo.pageNum}页,总${pageInfo.pages}页,总共${pageInfo.total}记录</h4>
</div>
<%--分页条信息--%>
<div class="col-md-6">
<nav aria-label="Page navigation">
<ul class="pagination">
<li><a href="${road}/emps?pn=1">首页</a></li>
<%--判断是否为第一页,是第一页就让前进按钮取消--%>
<c:if test="${pageInfo.hasPreviousPage}">
<li>
<a href="${road}/emps?pn=${pageInfo.pageNum-1}" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
</c:if>
<c:forEach items="${pageInfo.navigatepageNums}" var="num">
<%--添加高亮,和第一页禁用首页,最后一页禁用末页选项--%>
<c:if test="${num==pageInfo.pageNum}">
<li class="active"><a href="#">${num}</a></li>
</c:if>
<c:if test="${num!=pageInfo.pageNum}">
<li ><a href="${road}/emps?pn=${num}">${num}</a></li>
</c:if>
</c:forEach>
<c:if test="${pageInfo.hasNextPage}">
<li>
<a href="${road}/emps?pn=${pageInfo.pageNum+1}" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
</c:if>
<li><a href="${road}/emps?pn=${pageInfo.pages}">末页</a></li>
</ul>
</nav>
</div>
</div>
</div>
</body>
</html>
页面的效果:
3.将查询改造成AJAX
3.1 原因
为了不同平台的访问我们的页面都十分的方便,什么数据都是以json的形式返回,解析起来毫不费力
3.2 步骤
- 导包,在前期准备环境的时候已经在目录里面,没有导的可以再参考一下
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.12.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.12.1</version>
</dependency>
- 改造controller
- 改造list.jsp
3.3 改造controller
创建返回的为一个通用json类的controller
/**
* 以返回json的形式改写查询员工的方法
* @param pn
* @param model
* @return
*/
@RequestMapping("/emps")
@ResponseBody
public GeneralReturnJson getEmpsWithJson(@RequestParam(value = "pn", defaultValue = "1") Integer pn, Model model){
//为了分页查询,我们引入一个PageHelper分页插件
//在查询之前只需要调用startPage,从第几页开始查,每页几个
PageHelper.startPage(pn,5);
List<Employee> employees = employeeService.getAllEmps();
//查询完后pageInfo来包装查询后的结果(封装了详细的分页信息,包括我们查询出来的数据)
// 只需要把这个pageInfo给页面后就不需要在关心什么了
//传入连续显示的页数
PageInfo page = new PageInfo(employees,5);
//直接return
return GeneralReturnJson.success().add("pageInfo", page);
}
创建通用返回类
/**
* 通用的返回的类
*/
public class GeneralReturnJson {
//代表状态码,例如自己指定100等于成功,200等于失败
private int code;
//提示错误信息
private String msg;
//用户要返回给浏览器的数据
private Map<String, Object> extend = new HashMap<>();
//定义成功返回信息
public static GeneralReturnJson success(){
GeneralReturnJson result = new GeneralReturnJson();
//这里我们用3697代表成功
result.setCode(3697);
result.setMsg("处理成功!");
return result;
}
//定义失败返回信息
public static GeneralReturnJson fail(){
GeneralReturnJson result = new GeneralReturnJson();
//这里我们用627代表失败
result.setCode(627);
result.setMsg("处理失败!");
return result;
}
//定义添加用户数据的add方法
public GeneralReturnJson add(String key, Object value){
this.getExtend().put(key,value);
return this;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public Map<String, Object> getExtend() {
return extend;
}
public void setExtend(Map<String, Object> extend) {
this.extend = extend;
}
}
3.4 改造改造list.jsp
改造list.jsp之间先要把index.jsp的交互逻辑改变:
- 以前的是进入index后发请求然后跳转到list页面
- 现在是进入index后让其发送ajax请求然后获取到json对象的数据,然后解析在页面进行显示
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%
pageContext.setAttribute("road",request.getContextPath());
%>
<!-- 加载 Bootstrap 的所有 JavaScript 插件。你也可以根据需要只加载单个插件。 -->
<script src="static/bootstrap-3.4.1-dist/js/bootstrap.js"></script>
<!-- Bootstrap -->
<link rel="stylesheet" href="static/bootstrap-3.4.1-dist/css/bootstrap.css">
<script type="text/javascript" src="static/js/jquery-3.5.1.js"></script>
<html>
<head>
<title>员工列表</title>
</head>
<body>
<%--搭建显示页面,简单分别四行来显示--%>
<div class="container">
<%--标题--%>
<div class="row">
<div class="col-md-12">
<h1>SSM-ITEM</h1>
</div>
</div>
<%--按钮--%>
<div class="row">
<div class="col-md-4 col-md-offset-8">
<button class="btn btn-primary">新增</button>
<button class="btn btn-danger">删除</button>
</div>
</div>
<%--显示表格信息--%>
<div class="row">
<div class="col-md-12">
<table class="table table-hover" id="emps_table">
<thead>
<tr>
<th>#id</th>
<th>empName</th>
<th>gender</th>
<th>email</th>
<th>department</th>
<th>操作</th>
</tr>
<tbody></tbody>
</thead>
</table>
</div>
</div>
<%--显示分页信息按钮--%>
<div class="row">
<%--分页文字信息--%>
<div class="col-md-6" id="build_page_info">
<h4></h4>
</div>
<%--分页条信息--%>
<div class="col-md-6" id="build_page_msg">
</div>
<script type="text/javascript">
//1.页面加载完成后,直接去发送一个ajax请求,要到分页数据
$(function (){
//第一次进来去第一页
to_page(1)
});
function to_page(pn){
$.ajax({
url:"${road}/emps",
data:"pn="+pn,
type:"get",
success:function (result){
//1.拿到数据后,解析并显示员工数据
build_emps_table(result);
//2.解析并显示分页信息
build_page_info(result);
//3.解析显示分页条信息
build_page_msg(result);
}
});
};
function build_emps_table(result){
//每次去新的页面将之前的ajax数据清除
$("#emps_table tbody").empty();
var emps = result.extend.pageInfo.list;
$.each(emps, function (index, item){
var empIdTd = $("<td></td>").append(item.empId);
var empNameTd = $("<td></td>").append(item.empName);
var genderTd = $("<td></td>").append(item.gender);
var emailTd = $("<td></td>").append(item.email);
var deptNameTd = $("<td></td>").append(item.department.deptName);
var editBtn = $("<button></button>").addClass("btn btn-success btn-sm")
.append($("<span></span>").addClass("glyphicon glyphicon-pencil"))
.append("编辑");
var delBtn = $("<button></button>").addClass("btn btn-info btn-sm")
.append($("<span></span>").addClass("glyphicon glyphicon-trash"))
.append("新增");
var btnTd = $("<td></td>").append(editBtn).append(" ").append(delBtn);
//使用jQuery添加显示员工信息的单元格
$("<tr></tr>").append(empIdTd).append(empNameTd)
.append(genderTd).append(emailTd).append(deptNameTd)
.append(btnTd)
.appendTo("#emps_table tbody");
});
}
//解析显示分页信息
function build_page_info(result){
//每次去新的页面将之前的ajax数据清除
$("#build_page_info h4").empty();
$("#build_page_info h4").append("当前"+result.extend.pageInfo.pageNum+ "页,总"
+result.extend.pageInfo.pages+"页,总共"
+result.extend.pageInfo.total+"记录")
}
//解析分页条
function build_page_msg(result){
//每次去新的页面将之前的ajax数据清除
$("#build_page_msg").empty();
var ul=$("<ul></ul>").addClass("pagination");
var firstPageLi = $("<li></li>").append($("<a></a>").append("首页").attr("href","#"));
var prePageLi = $("<li></li>").append($("<a></a>").append("«"));
if(result.extend.pageInfo.hasPreviousPage == false){
firstPageLi.addClass("disabled");
prePageLi.addClass("disabled");
}else {
firstPageLi.click(function (){
to_page(1);
});
prePageLi.click(function (){
to_page(result.extend.pageInfo.pageNum-1);
});
}
var lastPageLi = $("<li></li>").append($("<a></a>").append("»"));
var nextPageLi = $("<li></li>").append($("<a></a>").append("末页").attr("href","#"));
if(result.extend.pageInfo.hasNextPage == false){
nextPageLi.addClass("disabled");
lastPageLi.addClass("disabled");
}else {
lastPageLi.click(function (){
to_page(result.extend.pageInfo.pages);
});
nextPageLi.click(function (){
to_page(result.extend.pageInfo.pageNum+1);
});
}
//添加首页和前一页的的提示
ul.append(firstPageLi).append(prePageLi);
//遍历给ul添加页码提示
$.each(result.extend.pageInfo.navigatepageNums, function (index, item){
var numLi = $("<li></li>").append($("<a></a>").append(item));
if(result.extend.pageInfo.pageNum == item){
numLi.addClass("active")
}
numLi.click(function (){
to_page(item);
});
ul.append(numLi);
});
//添加下一页和末页的提示
ul.append(nextPageLi).append(lastPageLi);
//把ul加入到nav
var navEle = $("<nav></nav>").append(ul);
navEle.appendTo("#build_page_msg");
}
</script>
</div>
</div>
</body>
</html>
为了避免页面跳转出现问题
我们在mybatis的xml文件中添加一个属性值,使之能够页面切换合理化
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor">
<!--调整分页参数合理化,最后一页之后不会出现-1页,而首页之前也不会出现+1-->
<property name="reasonable" value="true"/>
</plugin>
</plugins>
改完效果还是跟以前一样,不过我们现在使用ajax来显示页面,可以不用跳转
末尾:博主突然做着做着不想写在这上面了 累死了-.-,所以还想要源码的可以去我的GitHub上拿
遇到的错误
1.驼峰命名规范
编写的测试代码
/**
* 测试dao层是否能正常工作
* 这里我们使用spring中的spring-test来测试,让mapper自动注入IOC容器中
*/
@RunWith(SpringJUnit4ClassRunner.class)
/*指定配置文件的位置*/
@ContextConfiguration(locations = "classpath:application.xml")
public class MapperTest {
/*用Autowired注解直接自动注入*/
@Autowired
DepartmentMapper departmentMapper;
@Test
public void testAddDept(){
/*//1.创建SpringIOC容器
ApplicationContext ac = new ClassPathXmlApplicationContext("application.xml");
//2.从容器里面获取mapper
DepartmentMapper bean = ac.getBean(DepartmentMapper.class);*/
System.out.println(departmentMapper);
}
}
在环境搭建中的测试CRUD的操作过程中,遇到了莫名其妙的错误
经过半天的寻找,发现是mybatis-config.xml里面的驼峰命名规范造成的这个问题,在spring配置文件中可能有众多名称没有遵循,所以我建议大家还是不要开启了
将以下这段注释注释掉即可成功运行
<settings>
<!--配置驼峰命名规则-->
<setting name="mapUnderscoreToCamelCase " value="true"/>
</settings>
运行成功
2.指出mybatis全局配置文件的位置错误
测试代码
@RunWith(SpringJUnit4ClassRunner.class)
/*WebAppConfiguration这个注解就是为了配置在spring中没有配置的ioc容器
* WebApplicationContext就是在spring配置文件中没有配置的,所以采用这个方式
* */
@WebAppConfiguration
/*指定配置文件的位置*/
@ContextConfiguration(locations = {"classpath:application.xml", "classpath:springMVC.xml"})
public class MvcTest {
//传入springMVC的ioc容器
@Autowired
WebApplicationContext context;
//虚拟MVC的请求,获取到处理的结果
MockMvc mockMvc;
//初始化创建mockMvc
@Before
public void initMokMvc(){
mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
}
@Test
public void testPage() throws Exception{
//模拟请求拿到返回值
MvcResult result = mockMvc.perform(MockMvcRequestBuilders.get("/emps")
.param("pn", "1")).andReturn();
//请求成功以后,请求域中会有pageInfo,我们可以取出并进行验证
MockHttpServletRequest request = result.getRequest();
PageInfo pageInfo = (PageInfo) request.getAttribute("pageInfo");
System.out.println("当前页码为:"+pageInfo.getPageNum());
System.out.println("总页码:"+pageInfo.getPages());
System.out.println("总记录数:"+pageInfo.getTotal());
System.out.println("在页面需要连续显示的页码");
int[] nums = pageInfo.getNavigatepageNums();
for(int i: nums){
System.out.print(""+i);
}
//获取员工数据,因为我们一并将员工信息包装到了pageInfo
List<Employee> list = pageInfo.getList();
for (Employee employee : list) {
System.out.println();
}
}
}
显示异常
解决方案:在spring的配置文件中,配置mybatis的路径一定要把classpath加上
<!--配置与Mybatis的整合-->
<bean id="SessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--指出mybatis全局配置文件的位置-->
<property name="configLocation" value="classpath:mybatis-config.xml"></property>
<!--指定数据源,因为前面已经配置好了数据源,所以直接用ref引用即可-->
<property name="dataSource" ref="dataSource"></property>
<!--只用mybatis的mapper文件位置-->
<property name="mapperLocations" value="classpath:mapper/*.xml"></property>
</bean>
问题解决
3.UnsatisfiedDependencyException
错误发生时间:工程写到实现功能里面的第一个查询员工信息(分页查询)
然后第一次启动服务器出现这个异常
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'employeeController': Unsatisfied dependency expressed through field 'employeeService'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.lhjitem.service.EmployeeService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:643)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:119)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:399)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1415)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:608)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:531)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:944)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:923)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:588)
at org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:702)
at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:668)
at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:716)
at org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:591)
at org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:530)
at org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:170)
at javax.servlet.GenericServlet.init(GenericServlet.java:158)
at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1134)
at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1089)
at org.apache.catalina.core.StandardWrapper.allocate(StandardWrapper.java:761)
at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:686)
at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:457)
at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:384)
at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:312)
at org.apache.jasper.runtime.PageContextImpl.forward(PageContextImpl.java:528)
at org.apache.jsp.index_jsp._jspService(index_jsp.java:124)
at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:71)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:733)
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:467)
at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:378)
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:326)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:733)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:94)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:687)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:893)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1707)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.lhjitem.service.EmployeeService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1790)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1346)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1300)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:640)
... 64 more
解决方法:在web.xml中配置两个监听器
<!--读取Spring上下文的监听器-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Spring和web项目集成end -->
<!-- 防止Spring内存溢出监听器 -->
<listener>
<listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
</listener>
问题解决,成功访问:
4.单选框的value
穿进去的数据使value值,而不是input后面的提示选择值,如果value没设置或是默认的长字符就会跟数据库的属性的长度发生冲突导致异常