一、搭建开发环境
1.新建 Dynamic Web project
2. 配置 spring
a. 加入 spring 和 springMVC的jar 包
b. 在 web.xml 中配置启动 IOC 容器的 Listener: ContextLoadListener
classpath:applicationContext.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
c. 新建 appliacationContext.xml
3. 配置 SpringMVC
a. web.xml 中配置 SpringMVC 的 DispatcherServlet url 改为 /
<servlet>
<servlet-name>springDispatcherServlet</servlet-name>
<servlet class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springDispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
b. 在 WEB-INF下 新建 springDispatchServlet-servlet.xml 文件
c. web.xml 中配置字符编码过滤器 必须配置在所有过滤器的最前面
<filter>
<filter-name>CharacterEncodingFilter</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>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
d. web.xml 配置可以把 POST 请求转为 PUT,DELETE 请求的 Filter
<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>
springDispatcherServlet-servlet.xml:
a. 配置自动扫描的包 只扫描 Controller 和 ControllerAdvice
<context:component-scan base-package=“com.atguigu.sssp” use-default-filters=“false”>
<context:include-filter type=“annotation” expression=“org.springframework.stereotype.Controller”/>
<context:include-filter type=“annotation” expression=“org.springframework.web.bind.annotation.ControllerAdvice”/>
</context:component-scan>
b. 配置视图解析器 prefix - /WEB-INF/views/ 新建 views 文件夹
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
c. 两个 mvc 标配
<mvc:default-servlet-handler/>
<mvc:annotation-driven></mvc:annotation-driven>
- 加入JPA
a. 加入 jpa jar 包 c3p0 二级缓存
applicationContext.xml:
b. 配置自动扫描的包 不扫描 Controller 和ControllerAdvice
<context:component-scan base-package="com.atguigu.sssp">
<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>
c. 配置数据源 新建资源文件 db.properties
<!-- 配置数据源 -->
<context:property-placeholder location="classpath:db.properties"/>
<bean id="dataSource"
class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="${jdbc.user}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="driverClass" value="${jdbc.driverClass}"></property>
<property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
<!-- 配置其他属性 -->
</bean>
db.properties
jdbc.user=root
jdbc.password=1275485428
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.jdbcUrl=jdbc:mysql:///spring
d. 测试 DataSource 是否配置成功
e. 配置 JPA 的 EntityManagerFactory 有二级缓存、shareCacheMode
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"></bean>
</property>
<property name="packagesToScan" value="com.atguigu.sssp"></property>
<property name="jpaProperties">
<props>
<prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</prop>
<prop key="hibernate.cache.use_query_cache">true</prop>
</props>
</property>
<property name="sharedCacheMode" value="ENABLE_SELECTIVE"></property>
</bean>
f. 配置事务
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"></property>
</bean>
g. 配置支持基于注解的事务
<tx:annotation-driven transaction-manager="transactionManager"/>
- 配置 SpringData
a. 加入 springdata jar 包
applicationContext.xml
b. 配置 springData 自动扫描的包
<jpa:repositories base-package="com.atguigu.sssp"
entity-manager-factory-ref="entityManagerFactory"></jpa:repositories>
二、实体类
- 新建 Employee(birth, createTime,department,email,id,lastName) 和 Department (ID,departmentName)
- 添加对应的注解 ManyToOne(fetch=FetchType.LAZY)
- test 创建对应 table
三、完成分页操作
-
创建一个接口 interface EmployeeRepository extends JpaRepositorypublic interface EmployeeRepository extends JpaRepository<Employee, Integer> {}(内容为空)
-
创建一个类 EmployeeService
@Service
public class EmployeeService {@Autowired
private EmployeeRepository employeeRepository;@Transactional(readOnly=true)
public Page getPage(int pageNo, int pageSize){
PageRequest pageable = new PageRequest(pageNo - 1, pageSize);
return employeeRepository.findAll(pageable);
}
} -
创建一个类 EmployeeHandler (Controller 类)
@Controller
public class EmployeeHandler {
@Autowired
private EmployeeService employeeService;
@RequestMapping("/emps")
public String list(@RequestParam(value="pageNo", required=false, defaultValue="1") String pageNoStr,
Map<String, Object> map){
int pageNo = 1;
try {
pageNo = Integer.parseInt(pageNoStr);
if(pageNo < 1){
pageNo = 1;
}
} catch (Exception e) {}
Page<Employee> page = employeeService.getPage(pageNo, 5);
map.put("page", page);
return "emp/list";
}
}
4. 创建 list.jsp
<c:if test="
p
a
g
e
=
=
n
u
l
l
∣
∣
p
a
g
e
.
n
u
m
b
e
r
O
f
E
l
e
m
e
n
t
s
=
=
0
"
>
没
有
任
何
记
录
!
<
/
c
:
i
f
>
<
c
:
i
f
t
e
s
t
=
"
{page == null || page.numberOfElements == 0 }"> 没有任何记录! </c:if> <c:if test="
page==null∣∣page.numberOfElements==0">没有任何记录!</c:if><c:iftest="{page != null && page.numberOfElements > 0 }">
<table cellpadding=“10” cellspacing=“0” border=“1”>
<tr>
<th>ID</th>
<th>LASTNAME</th>
<th>EMAIL</th>
<th>BIRTH</th>
<th>CREATETIEM</th>
<th>DEPARTMENT</th>
<th>EDIT</th>
<th>DELETE</th>
</tr>
<c:forEach items="${page.content }" var=“emp”>
<td>${emp.id }</td>
<td>${emp.lastName }</td>
<td>${emp.email }</td>
<td>
<fmt:formatDate value="
e
m
p
.
b
i
r
t
h
"
p
a
t
t
e
r
n
=
"
y
y
y
y
−
M
M
−
d
d
"
/
>
<
/
t
d
>
<
t
d
>
<
f
m
t
:
f
o
r
m
a
t
D
a
t
e
v
a
l
u
e
=
"
{emp.birth }" pattern="yyyy-MM-dd"/> </td> <td> <fmt:formatDate value="
emp.birth"pattern="yyyy−MM−dd"/></td><td><fmt:formatDatevalue="{emp.createTime }" pattern=“yyyy-MM-dd hh:mm:ss”/>
</td>
<td>${emp.department.departmentName }</td>
<td><a href="">edit</a></td>
<td><a href="">delete</a></td>
</tr>
</c:forEach>
<tr>
<td colspan="8">
共 ${page.totalElements } 条记录数
共 ${page.totalPages } 页
当前第 ${page.number + 1 } 页
<a href="?pageNo=${page.number + 1 - 1 }">上一页</a>
<a href="?pageNo=${page.number + 1 + 1 }">下一页</a>
</td>
</tr>
</table>
</c:if>
- index.jsp
- web.xml 添加 OpenEntityManagerInViewFilter 解决懒加载异常
<filter>
<filter-name>OpenEntityManagerInViewFilter</filter-name>
<filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>OpenEntityManagerInViewFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
四、完成添加操作(二级缓存)
- 创建接口 DepartmentRepository extends JpaRepository
- 添加 ehcache.xml
- Department 类 添加注解 @Cacheable
- test
- DepartmentRepository
定义
@QueryHints({@QueryHint(name=org.hibernate.ejb.QueryHints.Hint_CACHEABLE,value=“true”)})
@Query(“FROM Department d”)
List<Department> getAll(); - DepartmentService
- 在 EmployeeHandler 中编写 input 方法 method=RequestMethod.GET
- 创建 input.jsp 使用 form 标签
五、Ajax 验证
- EmployeRepository 接口添加 Employee getByLastName(String lastName); 方法
- EmployeeService 类继承 getByLastName 方法
- EmployeeHandler 创建 validateLastName 验证 LastName 对应的Employee是否存在
加上 @ResponseBody 注解(返回Ajax)
@ResponseBody
@RequestMapping(value=“ajaxValidateLastName”, method=RequestMethod.POST)
public String validateLastName(@RequestParam(“lastName”) String lastName){
if(employeeService.getByLastName(lastName) == null){
return “1”;
}else{
return “0”;
}
} - input.jsp 导入 jQuery ${pageContext.request.contextPath } 编写 lastName change 函数
$("#lastName").change(function(){
var url = “ajaxValidateLastName”
var val = $(this).val();
val = $.trim(val);
var args = {
“lastName” : val,
“time” : new Date()
};
if(val != “”){
$.post(url, args, function(data) {
if (data == “1”) {
alert(“该名字可用!”);
} else if (data == “0”) {
alert(“该名字不可用!”);
} else {
alert(“服务器出错!”);
}
});
}
六、完成添加
- EmployeeService 添加 saveAndFlush 方法 (EmployeeRepository 继承父类不用写)
还要写上 if employee.getId() == null 的情况下, 添加 new createTime - EmployeeHandler
- birth 添加 @DateTimeFormat(pattern=“yyyy-MM-dd”) 注解 添加了才跑得动
补充:
<fmt:formatDate value="${emp.createTime }" pattern=“yyyy-MM-dd HH:mm:ss”/>
HH:mm:ss:大写HH 24小时时间制
hh:mm:ss:小写hh 12 小时时间制
七、表单回显
- EmployeeRepository 不添加 继承父类 findOne 方法
- EmployeeService 类添加 findOne 方法
- EmployeeHandler 类 添加回显方法,注意使用 @PathVariable 注解接收 url 传来的参数
@RequestMapping(value="/emp/{id}", method=RequestMethod.GET)
public String edit(@PathVariable(“id”) Integer id,
Map<String, Object> map){
Employee employee = employeeService.findOne(id);
map.put(“departments”, departmentService.getAll());
map.put(“employee”, employee);
return “emp/input”;
} - list.jsp 中完善 edit a 超链接 href="${pageContext.request.contextPath}/emp/${emp.id}"
八、修改状态下的 Ajax
- input.jsp 中用c 标签,添加隐藏域存放以前的 lastName
//<form:hidden/> 用于提交 回显
//<input type=“hidden”> 不用提交和回显
<c:if test=" e m p l o y e e . i d ! = n u l l > < i n p u t t y p e = " h i d d e n " i d = " o l d L a s t N a m e " v a l u e = " {employee.id} != null> <input type="hidden" id="oldLastName" value=" employee.id!=null><inputtype="hidden"id="oldLastName"value="{employee.lastName}">
</c:if>
九、完成修改
补充:解决中文乱码:在 db.properties 中修改jdbc.jdbcUrl 为:
jdbc.jdbcUrl=jdbc:mysql:///jpa2?characterEncoding=utf-8
createTime 不修改
-
完善 input.jsp 页面 注意此时: action="${url }"
<c:set value="${pageContext.request.contextPath }/emp" var=“url”></c:set>
<c:if test=" e m p l o y e e . i d ! = n u l l " > < c : s e t v a l u e = " {employee.id != null }"> <c:set value=" employee.id!=null"><c:setvalue="{pageContext.request.contextPath }/emp/${employee.id }" var=“url”>
</c:set>
</c:if><form:form action="${url }" method=“POST” modelAttribute=“employee” >
<c:if test="${employee.id != null }"> <input type="hidden" id="oldLastName" value="${employee.lastName }"> <form:hidden path="id"/> <input type="hidden" name="_method" value="PUT"> </c:if>
-
EmployeeHandler
a. 添加update 方法
@RequestMapping(value="/emp/{id}", method=RequestMethod.PUT)
public String update(@PathVariable(“id”) Integer id, Employee employee){
System.out.println(employee);
employeeService.saveAndFlush(employee);
return “redirect:/emps”;
}
b. 添加 @ModelAttribute 方法
@ModelAttribute
public void getEmployee(@RequestParam(value=“id”, required=false) Integer id,
Map<String, Object> map){
if(id != null){
map.put(“employee”, employeeService.findOne(id));
}
}
十、 解决 department 修改问题
在 ModelAttribute 方法中,department 置空 ,employee.setDepartment(null);
十一、删除
- EmployeeRepository 继承父类 delete 不需要添加
- EmployeeService 添加 delete(Integer id) 方法
- EmployeeHandler 添加 delete 方法
@RequestMapping(value="/emp/{id}", method=RequestMethod.DELETE)
public String delete(@PathVariable(“id”) Integer id){
System.out.println(“hlo”);
employeeService.delete(id);
return “redirect:/emps”;
} - list.jsp
$(".delete").click(function(){
var href = $(this).attr(“href”);
var lastName = $(this).next(":hidden").val();
var flag = confirm(“确定要删除 " + lastName + " 的信息吗?”);
if(flag == true){
$("#_form").attr(“action”, href).submit();
}
return false;
});
<form:form action="" method=“POST” id="_form">
<input type=“hidden” name="_method" value=“DELETE”>
</form:form>
。。。
<td><a class=“delete” href="${pageContext.request.contextPath }/emp/${emp.id}">delete</a>
<input type=“hidden” value="${emp.lastName }">
</td>