常用依赖
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!--spring依赖包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
<!--spring连接MySQL的依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
<!-- aspectj切面-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
<!--mybatis-spring整合包-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.5</version>
</dependency>
<!--servlet,有tomcat依赖包时不需要导入servlet的依赖-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!--mysql驱动8.0.11-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.11</version>
<scope>compile</scope>
</dependency>
<!--druid连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.22</version>
</dependency>
<!--jstl依赖-->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!--servlet系列:servlet\jsp\jstl-->
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet/jsp-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet/jstl -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!--json数据处理-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.59</version>
</dependency>
<!--mysql驱动5.1.6-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<!--log4j,日志-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<!--自动配置实体类-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<!--jackson,json数据解析工具-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.11.0</version>
</dependency>
</dependencies>
###mybatis-config.xml配置
数据库连接后面会放到spring中实现
<?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>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="org/mybatis/example/BlogMapper.xml"/>
</mappers>
</configuration>
手动实现代理
利用反射
public class ProxyInvocationHandler implements InvocationHandler {
private Object target;
//设置真实用户
public void setTarget(Object target) {
this.target = target;
}
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
seeHouse();
//这里是通过反射执行被代理对象的业务
Object result=method.invoke(target,args);
return result;
}
//这里是代理的业务
public void seeHouse(){
System.out.println("看房");
}
}
###maven中静态资源和字节码文件的过滤
配置mapper时碰到XXXmapper.xml不输出到target的问题
问题报错
org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.ysq.mapper.UserMapper.queryAllUser
解决方法,在pom.xml中配置
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
</build>
@Autowired 注入失效问题
使用Junit测试时,如果需要使用上下文context(比如自动注入),必须指定spring环境
注:Junit版本需要4.12以上
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:applicationContext.xml"})
404警告
The origin server did not find a current representation for the target resource or is not willing to disclose that one exists.
根据教程,一开始以为是没配 lib,配了之后还是这个错误,后来才发现Controller没实例化,尴尬了
<bean id="/hello" class="com.ysq.controller.HelloController"/>
springMVC的快速搭建
准备工作:
添加web支持(javaEE 4+);
导入所有jar包到lib
- 配置Web.xml
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
2.配置springmvc-servlet
<context:component-scan base-package="com.ysq.*"/>
<!--不过滤静态文件-->
<mvc:default-servlet-handler/>
<!--启动RequestMapping注解-->
<mvc:annotation-driven/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
id="internalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
3.创建Controller(注解方式)
@Controller
public class HelloController {
@RequestMapping("/hello")
public String hello(Model model){
//封装数据
model.addAttribute("msg","hello Shane!!");
return "hello";
}
}
4.根据请求跳转页面
jsp、HTML之类的页面
@RequestMapping的注意点
- 在类上注解和方法上注解
类上注解的路径会成为所有方法的父路径
以下路径会是:/calculate/add、/calcaulate/sub
@Controller
@RequestMapping("/calculate")
public class ResFullController {
@RequestMapping("/add")
public String getAdd(Model model){
model.addAttribute("result",a+b);
return "result";
}
@RequestMapping("/sub")
public String getAdd(Model model){
//model.addAttribute("result",a+b);
//...
return "result";
}
}
- 路径参数
@RequestMapping("/add/{a}/{b}")
public String getAdd(@PathVariable int a,@PathVariable int b, Model model){
model.addAttribute("result",a+b);
return "result";
}
- 请求方式
通过参数method:GET、POST、PUT、DELETE
@RequestMapping(path="/add/{a}/{b}",method = RequestMethod.DELETE)
public String getAdd(@PathVariable int a,@PathVariable int b, Model model){
model.addAttribute("result",a+b);
return "result";
}
- 请求方式另一种方式是使用注解
@GetMapping("…")、@DeleteMapping("…")
可以实现同一路径不同方法
@GetMapping("/sub/{a}/{b}")
public String Sub(@PathVariable int a,@PathVariable int b,Model model){
model.addAttribute("result",a-b);
return "result";
}
@PostMapping("/sub/{a}/{b}")
public String Sub2(@PathVariable int a,@PathVariable int b,Model model){
model.addAttribute("result",b-a);
return "result";
}
网页乱码问题
使用过滤器Filter解决
1.添加过滤器
public class EncodingFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
}
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
servletRequest.setCharacterEncoding("UTF-8");
servletResponse.setCharacterEncoding("UTF-8");
}
public void destroy() {
}
}
2.配置到web.xml
<filter>
<filter-name>filter</filter-name>
<filter-class>com.ysq.filter.EncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>filter</filter-name>
<url-pattern>/</url-pattern>
</filter-mapping>
3.以上的方法只能解决GET方式下的乱码,POST方式请求仍然报错
尝试使用spring自带的过滤器,还是解决不了POST请求
<filter>
<filter-name>encoding</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>encoding</filter-name>
<url-pattern>/</url-pattern>
</filter-mapping>
4.最后仔细看一下才发现写错了
这里应该用 /* 表示过滤所有jsp,而不是 /
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
###只请求数据,不需要转到视图时
使用@ResponseBody
@RequestMapping("/json")
@ResponseBody //直接返回值,而不是导向视图解析器
public String getJSon(){
User user=new User();
return "json";
}
或者直接在类上添加注解@RestController
这个时候也不需要写@Controller,相当于把这个Controller类当做数据请求中心,一般在严格的前后端项目中使用
@RestController
public class userController {
@RequestMapping(value = "/json")
public String getJSon() throws JsonProcessingException {
User user=new User(12,"你好,Shane",18);
ObjectMapper mapper=new ObjectMapper();
return mapper.writeValueAsString(user);
}
}
json数据乱码问题
- 第一种方法是在RequestMapping中设置produces
但是这种方法需要在每一个地方都设置,十分麻烦
@RequestMapping(value = "/json",produces = "application/json;charset=utf-8")
- 第二种方法是在spring-servlet.xml中统一设置
ps: json字符串会直接转换为json对象,可以在js中使用
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>application/json;charset=UTF-8</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
使用Jackson实现的一个快速工具类
- 重点在于使用ObjectMapper吧对象转换为json字符串
- 如果直接把Date 日期类型的对象传到前端,前端只能得到一个时间戳,
所以需要通过关闭时间戳模式和设置日期格式来获取想要的字符串。
public class JsonUtil {
public static String getJson(Object object){
ObjectMapper mapper=new ObjectMapper();
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,false);
SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd HH-mm-ss");
mapper.setDateFormat(format);
try {
return mapper.writeValueAsString(object);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
public static String getJson(Object object,String dateformat){
ObjectMapper mapper=new ObjectMapper();
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,false);
SimpleDateFormat format=new SimpleDateFormat(dateformat);
mapper.setDateFormat(format);
try {
return mapper.writeValueAsString(object);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
}
c3p0连接池xml常用配置
<context:property-placeholder location="classpath:database.properties"/>
<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}"/>
<!-- c3p0连接池的私有属性 -->
<property name="maxPoolSize" value="30"/>
<property name="minPoolSize" value="10"/>
<!-- 关闭连接后不自动commit -->
<property name="autoCommitOnClose" value="false"/>
<!-- 获取连接超时时间 -->
<property name="checkoutTimeout" value="10000"/>
<!-- 当获取连接失败重试次数 -->
<property name="acquireRetryAttempts" value="2"/>
</bean>
SSM整合
spring-dao.xml配置
<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"
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">
<context:property-placeholder location="classpath:database.properties"/>
<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}"/>
<!-- c3p0连接池的私有属性 -->
<property name="maxPoolSize" value="30"/>
<property name="minPoolSize" value="10"/>
<!-- 关闭连接后不自动commit -->
<property name="autoCommitOnClose" value="false"/>
<!-- 获取连接超时时间 -->
<property name="checkoutTimeout" value="10000"/>
<!-- 当获取连接失败重试次数 -->
<property name="acquireRetryAttempts" value="2"/>
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!--绑定mybatis配置文件-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--注入sqlSessionFactory-->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<!--扫描dao包-->
<property name="basePackage" value="com.ysq.mapper"/>
</bean>
</beans>
spring-service.xml配置
<!--扫描所有service类-->
<context:component-scan base-package="com.ysq.service"/>
<!--将业务类注入到spring-->
<bean id="UserServiceImpl" class="com.ysq.service.UserServiceImpl">
<property name="userMapper" ref="userMapper"/>
</bean>
<!--声明事务配置-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- AOP横切事务-->
SSM整合报错
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.ysq.service.UserService' available
找不到Service的Bean,但是在Test中通过ApplicationContext可以正常使用Bean。
可以确定时spring的问题,与底层无关。
经过检查,发现是web.xml中配错了,之前按习惯配了spring-mvc.xml,但是整合之后应该使用application-context.xml
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:application-context.xml</param-value>
</init-param>
横切事务提交
对数据库进行更新、删除操作时,事务不会自动提交,必须手动提交
<!-- AOP横切事务-->
<!--配置事务通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--给方法配置事务-->
<tx:attributes>
<tx:method name="add" propagation="REQUIRED"/>
<tx:method name="delete" propagation="REQUIRED"/>
<tx:method name="query" read-only="true"/>
<tx:method name="update" propagation="REQUIRED"/>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!--配置事务切入-->
<aop:config>
<aop:pointcut id="txPointcut" expression="execution(* com.ysq.mapper.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
</aop:config>
##事务提交失败
- 从前端提交到后端时取到的实体类对象时没有id字段的
//修改用户
@RequestMapping("/UpdateUser")
public String UpdateUser(User user){
userService.updateUser(user);
return "redirect:/user/allUsers";
}
- 解决方案:
前端传递隐藏域,例如:
<input type="hidden" value="${user.id}">
restFull实例
直接在地址栏中通过地址的方式传递参数
@RequestMapping(method = RequestMethod.POST, value = "/user/{id}")
public String delUser(@PathVariable("id") String uid) {
System.out.println("del:" + uid);
return "success";
}
注意使用jsp时必须在头部添加以下代码,否则foreach不会遍历
<%@ taglib prefix=“c” uri=“http://java.sun.com/jsp/jstl/core” %>
后端接收前端json数据失败
采用了@ResponseBody和@RequestBody,想要获取前端json数据直接转换为实体类对象。
前端
$.post({
url: url,
contentType:"application/json;charset=utf-8",
data: jsondata,
success: function (data) {
console.log(data);
layer.close(index1);
layer.close(index2);
var msg=layer.open({
title: false
,icon:1
,btn:"返回"
,content: '已完成'
,yes:function () {
layer.close(msg)
//$(location).attr("href", "${pageContext.request.contextPath}/user/toIndex")
}
});
}
后端
@RequestMapping(value = "/updateAppVersion",produces = "application/json;charset=utf-8")
@ResponseBody
public String UpdateAppVersion(HttpSession session,@RequestBody AppVersion appVersion){
///....
return JSON.toJSONString(success);
}
- 主要报错415,webType不支持之类的错误
- 这个问题搞了好久,检查过contentType和application/json之类的都写了。
- 查了好久,最后加上了Jackson依赖才终于正常运行,
看资料应该是因为RequestBody注解想要把json数据转换为实体类对象,就需要用到Jackson的方法。
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.11.0</version>
</dependency>