项目结构(配置文件方法)一
后台结构视图
前端结构视图
所需配置
pom.xml依赖包
<!--自定义属性-->
<properties>
<spring.version>5.3.1</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<!--springmvc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- Mybatis核心 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
<!--mybatis和spring的整合包-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>
<!-- 连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.9</version>
</dependency>
<!-- junit测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- MySQL驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
<!-- log4j日志 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.2.0</version>
</dependency>
<!-- 日志 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<!-- ServletAPI -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.1</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<!-- Spring5和Thymeleaf整合包 -->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>3.0.12.RELEASE</version>
</dependency>
</dependencies>
jdbc.properties数据库配置信息
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost/mybatis?serverTimezone=Asia/Shanghai
jdbc.username=root
jdbc.pwd=123456
log4g.xml日志文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
<param name="Encoding" value="UTF-8" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%-5p %d{MM-dd HH:mm:ss,SSS} %m (%F:%L) \n" />
</layout>
</appender>
<logger name="java.sql">
<level value="debug" />
</logger>
<logger name="org.apache.ibatis">
<level value="info" />
</logger>
<root>
<level value="debug" />
<appender-ref ref="STDOUT" />
</root>
</log4j:configuration>
mybatis-config.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>
<!--设置MyBatis的全局配置-->
<settings>
<!--将_下划线自动映射成驼峰-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<!--配置分页插件-->
<!--<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>-->
</configuration>
spring.xml配置文件
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!--扫描组件-->
<context:component-scan base-package="com.hwd.ssm">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!-- 引入jdbc.properties -->
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<!-- 配置Druid数据源 -->
<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.pwd}"></property>
</bean>
<!-- 配置用于创建SqlSessionFactory的工厂bean -->
<bean class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 设置MyBatis配置文件的路径 -->
<property name="configLocation" value="classpath:mybatis-config.xml">
</property>
<!-- 设置数据源 -->
<property name="dataSource" ref="dataSource"></property>
<!-- 设置类型别名所对应的包 -->
<property name="typeAliasesPackage" value="com.hwd.ssm.pojo">
</property>
<!--
设置映射文件的路径
若映射文件所在路径和mapper接口所在路径一致,则不需要设置
-->
<property name="mapperLocations" value="classpath:com/hwd/ssm/mapper/*.xml">
</property>
<!--分页插件-->
<property name="plugins">
<array>
<bean class="com.github.pagehelper.PageInterceptor"></bean>
</array>
</property>
</bean>
<!--
配置mapper接口的扫描配置,由mybatis-spring提供,将指定包下所有的mapper接口创建动态代理
并将这些动态代理作为IOC容器的bean管理
-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.hwd.ssm.mapper"></property>
</bean>
</beans>
springmvc配置文件
<?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: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 https://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.hwd.ssm.controller"></context:component-scan>
<!--配置视图解析器-->
<bean id="viewResolver"
class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
<property name="order" value="1"/>
<property name="characterEncoding" value="UTF-8"/>
<property name="templateEngine">
<bean class="org.thymeleaf.spring5.SpringTemplateEngine">
<property name="templateResolver">
<bean
class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
<!-- 视图前缀 -->
<property name="prefix" value="/WEB-INF/templates/"/>
<!-- 视图后缀 -->
<property name="suffix" value=".html"/>
<property name="templateMode" value="HTML5"/>
<property name="characterEncoding" value="UTF-8" />
</bean>
</property>
</bean>
</property>
</bean>
<!--配置默认的servlet处理静态资源-->
<mvc:default-servlet-handler></mvc:default-servlet-handler>
<!--开启注解驱动(如果不写,只能处理视图控制器的/的地址,处理不了控制层的请求映射)-->
<mvc:annotation-driven></mvc:annotation-driven>
<!--配置视图控制器-->
<mvc:view-controller path="/" view-name="index"></mvc:view-controller>
</beans>
使用配置类创建
结构
配置类
db.properties配置文件
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost/book?serverTimezone=Asia/Shanghai
jdbc.username=root
jdbc.pwd=123456
JdbcConfig配置类
使数据源和事务进行解耦
public class JdbcConfig {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.pwd}")
private String pwd;
//配置数据源
@Bean
public DataSource getDataSoure(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(driver);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(pwd);
return dataSource;
}
//配置数据源的事务
@Bean
public PlatformTransactionManager platformTransactionManager(DataSource dataSource){
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
transactionManager.setDataSource(dataSource);
return transactionManager;
}
}
Mybatis配置类
相当于配置文件的mybatis.xml文件
public class MyBatisConfig {
//配置SqlSessionFactoryBean
@Bean
public SqlSessionFactoryBean getSqlSessionFactoryBean(DataSource dataSource) throws IOException {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource);//设置数据源
//设置映射文件的路径
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
factoryBean.setMapperLocations(resolver.getResources("classpath*:/dao/*.xml"));
factoryBean.setTypeAliasesPackage("com.hwd.pojo");//设置类型别名所对应的包
return factoryBean;
}
/*
*
* 配置mapper接口的扫描配置,由mybatis-spring提供,
* 将指定包下所有的mapper接口创建动态代理
* 并将这些动态代理作为IOC容器的bean管理
* */
@Bean
public MapperScannerConfigurer mapperScannerConfigurer(){
MapperScannerConfigurer configurer = new MapperScannerConfigurer();
configurer.setBasePackage("com.hwd.dao");
return configurer;
}
}
SpringConfig配置类
相当于配置文件的spring.xml文件
//设置为配置类
@Configuration
//spring的配置扫描service层
@ComponentScan("com.hwd.service")
//加载properties
@PropertySource("classpath:db.properties")
//引入jdbc的配置类和mybatis的配置类
@Import({JdbcConfig.class,MyBatisConfig.class})
//配置事务
@EnableTransactionManagement
public class SpringConfig {
}
SpringMVCConfig配置类
相当于配置文件中的spring-mvc
@Configuration//标识为配置类
@ComponentScan("com.hwd.controller")//扫描组件
@EnableWebMvc//开启mvc的注解驱动resources
public class SpringMVCConfig implements WebMvcConfigurer {
//使用默认的servlet处理静态资源
//DispatcherServlet的URL进行筛查,如果发现是静态资源的请求,
// 就将该请求转由Web应用服务器默认的Servlet处理,如果不是静态资源的请求,
// 才由DispatcherServlet继续处理
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
//视图解析器配置
//配置生成模板解析器
@Bean
public ITemplateResolver templateResolver() {
WebApplicationContext webApplicationContext = ContextLoader.getCurrentWebApplicationContext();
// ServletContextTemplateResolver需要一个ServletContext作为构造参数,可通过WebApplicationContext 的方法获得
ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(webApplicationContext.getServletContext());
templateResolver.setPrefix("/WEB-INF/templates/");
templateResolver.setSuffix(".html");
templateResolver.setCharacterEncoding("UTF-8");
templateResolver.setTemplateMode(TemplateMode.HTML);
return templateResolver;
}
//生成模板引擎并为模板引擎注入模板解析器
@Bean
public SpringTemplateEngine templateEngine(ITemplateResolver templateResolver) {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver);
return templateEngine;
}
//生成视图解析器并未解析器注入模板引擎
@Bean
public ViewResolver viewResolver(SpringTemplateEngine templateEngine) {
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setCharacterEncoding("UTF-8");
viewResolver.setTemplateEngine(templateEngine);
return viewResolver;
}
//添加视图控制器<mvc:view-controller path="/" view-name="index"></mvc:view-controller>
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
}
//配置资源处理器,对于/static/**这种请求,不会被DispatcherServlet拦截,浏览器可以直接访问,当做静态资源交给Servlet处理-->
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**")
.addResourceLocations("/static/");
registry.addResourceHandler("/images/**")
.addResourceLocations("/images/");
}
Servlet配置类
相当于webapp下的web.xml
public class ServletConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
//加载Spring的配置
protected Class<?>[] getRootConfigClasses() {
return new Class[]{SpringConfig.class};
}
//加载springmvc配置
protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringMVCConfig.class};
}
//配置SpringMVC的前端控制器DispatchServlet的url-pattern
protected String[] getServletMappings() {
return new String[]{"/"};
}
//配置过滤器
@Override
protected Filter[] getServletFilters() {
//创建编码过滤器
CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
characterEncodingFilter.setEncoding("UTF-8");
characterEncodingFilter.setForceEncoding(true);
//创建处理请求方式的过滤器
HiddenHttpMethodFilter hiddenHttpMethodFilter = new HiddenHttpMethodFilter();
return new Filter[]{characterEncodingFilter,hiddenHttpMethodFilter};
}
}
改进版(dao,service,controller)
控制层改进Controller
1、控制类
@RestController
@RequestMapping("/books")
public class BookController {
@Autowired
private BookService bookService;
@PostMapping
public Result save(Book book){
boolean flag = bookService.save(book);
return new Result(flag ? Code.SAVE_OK : Code.SAVE_ERR,flag);
}
@DeleteMapping("/{id}")
public boolean delete(@PathVariable Integer id) {
return bookService.delete(id);
}
@GetMapping("/{id}")
public Result getById(@PathVariable Integer id) {
Book book = bookService.getById(id);
Integer code = book != null ? Code.GET_OK : Code.GET_ERR;
String msg = book != null ? "" : "数据查询失败";
return new Result(code,book,msg);
}
@GetMapping
public List<Book> getAll() {
return bookService.getAll();
}
}
2、进行结果封装Result
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Result {
//描述统一格式中的数据
private Object data;
//描述统一格式中的编码,用于区分操作,可以简化配置0或1表示成功失败
private Integer code;
//描述统一格式中的消息,可选属性
private String msg;
//构造方法是方便对象的创建
public Result(Integer code,Object data) {
this.data = data;
this.code = code;
}
//构造方法是方便对象的创建
public Result(Integer code, Object data, String msg) {
this.data = data;
this.code = code;
this.msg = msg;
}
}
dao层改进
public interface BookDao {
// @Insert("insert into tbl_book values(null,#{type},#{name},#{description})")
@Insert("insert into books values(#{bookName},#{price})")
void save(Book book);
@Update("update books set bookName = #{bookName},price = #{price} where id = #{id}")
void update(Book book);
@Delete("delete from books where id = #{id}")
void delete(Integer id);
@Select("select * from books where id = #{id}")
Book getById(Integer id);
List<Book> getAll();
}
注意:一般开发中sql语句要和dao层进行解耦,所以sql语句一般是使用配置文件mapper.xml
service业务层
@Service
public class BookServiceImpl implements BookService {
@Autowired
private BookDao bookDao;
public boolean save(Book book) {
bookDao.save(book);
return true;
}
public boolean update(Book book) {
bookDao.update(book);
return true;
}
public boolean delete(Integer id) {
bookDao.delete(id);
return true;
}
public Book getById(Integer id) {
Book book = bookDao.getById(id);
return book;
}
public List<Book> getAll() {
List<Book> list = bookDao.getAll();
return list;
}
}
注意:业务层的接口和dao层的接口返回类型有所改变
execption异常层
案例:
异常类
public class ControllerException extends RuntimeException {
private int statusCode;
public ControllerException(String message, int statusCode) {
super(message);
this.statusCode = statusCode;
}
public int getStatusCode() {
return statusCode;
}
}
controller层:
@RestController
@RequestMapping("/api")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/users/{id}")
public User getUser(@PathVariable Long id) {
User user = userService.getUser(id);
if (user == null) {
throw new ControllerException("User not found", HttpStatus.NOT_FOUND.value());
}
return user;
}
// other controller methods...
}
在上面的示例代码中,如果找不到指定 ID 的用户,将抛出 ControllerException 异常,并返回 404 状态码
接下来是异常处理器示例代码:
@RestControllerAdvice
public class ExceptionHandlerAdvice {
@ExceptionHandler(ControllerException.class)
public ResponseEntity<ErrorResponse> handleControllerException(ControllerException ex) {
ErrorResponse errorResponse = new ErrorResponse(ex.getMessage(), ex.getStatusCode());
return new ResponseEntity<>(errorResponse, HttpStatus.valueOf(ex.getStatusCode()));
}
// other exception handler methods...
}
在这个异常处理器中,当遇到 ControllerException 异常时,将把异常信息和状态码封装成一个 ErrorResponse 对象,并返回一个 ResponseEntity 对象作为响应。
ErrorResponse 类示例:
public class ErrorResponse {
private String message;
private int statusCode;
public ErrorResponse(String message, int statusCode) {
this.message = message;
this.statusCode = statusCode;
}
public String getMessage() {
return message;
}
public int getStatusCode() {
return statusCode;
}
}
最后是前端访问示例,我们可以使用 jQuery 发送一个 GET 请求获取用户信息:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>User Info</title>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body>
<h1>User Info</h1>
<div id="user-info"></div>
<script>
$.ajax({
url: "/api/users/1",
type: "GET",
dataType: "json",
success: function(data) {
$("#user-info").html("<p>User name: " + data.name + "</p><p>User age: " + data.age + "</p>");
},
error: function(jqXHR, textStatus, errorThrown) {
$("#user-info").html("<p>Error: " + jqXHR.status + " " + jqXHR.statusText + "</p>");
}
});
</script>
</body>
</html>
在这个示例代码中,我们使用 jQuery 发送一个 GET 请求获取 ID 为 1 的用户信息。如果用户不存在,将返回一个错误状态码,并在页面上显示错误信息。如果用户存在,则显示用户的姓名和年龄。
User Info
在这个示例代码中,我们使用 jQuery 发送一个 GET 请求获取 ID 为 1 的用户信息。如果用户不存在,将返回一个错误状态码,并在页面上显示错误信息。如果用户存在,则显示用户的姓名和年龄。