后端使用SpringJpa常见问题汇总
常见错误 ① no-session
原因懒加载引起(配置OpenEntityManagerInViewFilter在web.xml中)==
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1"> <!--注意:SpringMVC的配置和Spring的配置要单独读取,否则后面集成其它框架会出问题--> <!--读取Spring的配置 --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <!--配置的核心控制器DispatcherServlet--> <servlet> <servlet-name>dispatchServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!--读取SpringMvc配置--> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext-mvc.xml</param-value> </init-param> <!--tomcat启动优先级--> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatchServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <!--编码过滤--> <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> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!--配置过滤器(Spring为我们写好的:让我们EntityManager对象在页面展示完后再关闭解决noSesion问题(懒加载引起的)) 因为我们使用懒加载, 查询员工后EntityManager对象就关闭了,所以当页面再去加载department部门数据时就会发生no-session问题, 所以我们要延迟EntityManager对象关闭的时间 --> <filter> <filter-name>openEntityManager</filter-name> <filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class> </filter> <filter-mapping> <filter-name>openEntityManager</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- shiro的过滤器(帮我们拦截请求)-》什么事情都不做 Delegating:授(权); 把(工作、权力等)委托(给下级); 选派(某人做某事) Proxy:代理 -> 需要通过名称(shiroFilter)去找真正的过滤器 --> <filter> <filter-name>shiroFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <init-param> <param-name>targetFilterLifecycle</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>shiroFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
常见错误 ② no-serializer
原因序列化问题引起jpa的懒加载对象自己为填加了一些属性,(“hibernateLazyInitializer”,“handler”,“fieldHandler”) ,
这些属性会影响到SpringMVC返回Json(因为返回时有个内省机制,
因为你需要序列化对象有一个属性是一类类型,而你使用了Hibernate的延迟加载所以这里是个Hibernate的代理对象。该代理对象有些属性不能被序列化所以会报错。
所以忽略这些属性让其不参加序列化
解决方法一 :加注解(但是随着domain类的增多,工作量会加大)
解决方法二:配置xml一劳永逸
重写:ObjectMapper,然后在applicationContext-mvc.xml 配置这个映射(这个方法一劳永逸,之后在Spring集成JPA进行懒加载的时候,都会避免No serializer的错误
重写ObjectMapper关系映射
package cn.itsource.aisell.common; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; //重写了原生的映射关系 public class CustomMapper extends ObjectMapper { public CustomMapper() { this.setSerializationInclusion(JsonInclude.Include.NON_NULL); // 设置 SerializationFeature.FAIL_ON_EMPTY_BEANS 为 false this.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); } }
在applicationContext-mvc.xml 配置
<!--SpringMVC配置 解决No serializer问题--> <mvc:annotation-driven> <mvc:message-converters> <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> <property name="supportedMediaTypes"> <list> <value>application/json; charset=UTF-8</value> <value>application/x-www-form-urlencoded; charset=UTF-8</value> </list> </property> <!-- No serializer:配置 objectMapper 为我们自定义扩展后的 CustomMapper,解决了返回对象有关系对象的报错问题 --> <property name="objectMapper"> <bean class="cn.itsource.aisell.common.CustomMapper"></bean> </property> </bean> </mvc:message-converters> </mvc:annotation-driven>
常见错误 ③ n-to-n
错误原因 :持久化对象不可以修改Oid
解决方案:清空关连对象数据
后端代码EmployeeController代码
/** * 在你路径访问所有方法前都会先执行这个方法 * 还能接受前台数据 * 作用为修改方法创建一个对象包含所有信息 * @ModelAttribute("updateEmployee") 注解后面参数可以定位到具体方法把这个返回的对象返回给SpringMVC * 的对象复制一份给mvc的对象 * @param id * @param _cmd * @return */ @ModelAttribute("updateEmployee") public Employee beforeUpdate(Long id , String _cmd){ if (Objects.nonNull(id)&&Objects.equals("update",_cmd)){ //根据id查询到修改数据的信息放在临时对象中但这个对象是持久化状态所有不能修改关联部门表的id否则报n-to-n Employee tempEmployee = employeeService.findOne(id); //把关联对象设置为空,就可以解决n-to-n问题了 持久化对象不可以修改它的OID tempEmployee.setDepartment(null); return tempEmployee; } return null; }
/** * 修改的方法 * @param employee * @return * @ModelAttribute("updateEmployee")Employee employee此时mvc创建的Employee对象 * 就是@ModelAttribute("updateEmployee")方法返回的对象包含对应Employee的所有信息 * 用过前台传输数据进行属性注入此时密码一些信息就不会丢失而且因为关联对象department * 也清空了所有属性所以不会出现n-to-n问题了 */ @ResponseBody @RequestMapping("/update") public JsonResult update( @ModelAttribute("updateEmployee")Employee employee){ return saveOrUpdate(employee); }