【Maven基础】单一架构案例(二)

第三节 搭建环境:事务控制

1、总体思路

在这里插入图片描述

2、TransactionFilter

2.1、创建 Filter 类

在这里插入图片描述

2.2、TransactionFilter 完整代码

public class TransactionFilter implements Filter {

    // 声明集合保存静态资源扩展名
    private static Set<String> staticResourceExtNameSet;

    static {
        staticResourceExtNameSet = new HashSet<>();
        staticResourceExtNameSet.add(".png");
        staticResourceExtNameSet.add(".jpg");
        staticResourceExtNameSet.add(".css");
        staticResourceExtNameSet.add(".js");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        // 前置操作:排除静态资源
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        String servletPath = request.getServletPath();
        if (servletPath.contains(".")) {
            String extName = servletPath.substring(servletPath.lastIndexOf("."));

            if (staticResourceExtNameSet.contains(extName)) {

                // 如果检测到当前请求确实是静态资源,则直接放行,不做事务操作
                filterChain.doFilter(servletRequest, servletResponse);

                // 当前方法立即返回
                return ;
            }

        }

        Connection connection = null;

        try{

            // 1、获取数据库连接
            connection = JDBCUtils.getConnection();

            // 重要操作:关闭自动提交功能
            connection.setAutoCommit(false);

            // 2、核心操作
            filterChain.doFilter(servletRequest, servletResponse);

            // 3、提交事务
            connection.commit();

        }catch (Exception e) {

            try {
                // 4、回滚事务
                connection.rollback();
            } catch (SQLException ex) {
                ex.printStackTrace();
            }

            // 页面显示:将这里捕获到的异常发送到指定页面显示
            // 获取异常信息
            String message = e.getMessage();

            // 将异常信息存入请求域
            request.setAttribute("systemMessage", message);

            // 将请求转发到指定页面
            request.getRequestDispatcher("/").forward(request, servletResponse);

        }finally {

            // 5、释放数据库连接
            JDBCUtils.releaseConnection(connection);

        }

    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {}
    @Override
    public void destroy() {}
}

2.3、配置 web.xml

注意:需要首先将当前工程改成 Web 工程。

在这里插入图片描述

<filter>
    <filter-name>txFilter</filter-name>
    <filter-class>com.atguigu.imperial.court.filter.TransactionFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>txFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

2.4、注意点

2.4.1、确保异常回滚

在程序执行的过程中,必须让所有 catch 块都把编译时异常转换为运行时异常抛出;如果不这么做,在 TransactionFilter 中 catch 就无法捕获到底层抛出的异常,那么该回滚的时候就无法回滚。

2.4.2、谨防数据库连接提前释放

由于诸多操作都是在使用同一个数据库连接,那么中间任何一个环节释放数据库连接都会导致后续操作无法正常完成。

第四节 搭建环境:表述层

1、视图模板技术 Thymeleaf

1.1、服务器端渲染

除了我们熟悉的JSP,还有Velocity、Freemarker、Thymeleaf等视图模板技术。虽然具体语法各不相同,但是它们都有一个共通的特点,就是在固定内容中可以穿插表达式等形式的动态内容。将视图模板中的动态内容转换为对应的Java代码并执行,然后使用计算得到的具体数据替换原来的动态部分。这样整个文件的动态内容就可以作为确定的响应结果返回给浏览器。在这种模式下,前端工程师将前端页面全部开发完成,交给后端程序员加入到项目中。此时不可避免的需要后端程序员根据需要对前端代码进行补充和调整。

在这里插入图片描述

1.2、Thymeleaf 简要工作机制

1.2.1、初始化阶段
  • 目标:创建 TemplateEngine 对象
  • 封装:因为对每一个请求来说,TemplateEngine 对象使用的都是同一个,所以在初始化阶段准备好

在这里插入图片描述

1.2.2、请求处理阶段

在这里插入图片描述

1.3、逻辑视图与物理视图

假设有下列页面地址:

/WEB-INF/pages/apple.html
/WEB-INF/pages/banana.html
/WEB-INF/pages/orange.html
/WEB-INF/pages/grape.html
/WEB-INF/pages/egg.html

这样的地址可以直接访问到页面本身,我们称之为:物理视图。而将物理视图中前面、后面的固定内容抽取出来,让每次请求指定中间变化部分即可,那么中间变化部分就叫:逻辑视图

在这里插入图片描述

1.4、ViewBaseServlet 完整代码

为了简化视图页面处理过程,我们将 Thymeleaf 模板引擎的初始化和请求处理过程封装到一个 Servlet 基类中:ViewBaseServlet。以后负责具体模块业务功能的 Servlet 继承该基类即可直接使用。

public class ViewBaseServlet extends HttpServlet {

    private TemplateEngine templateEngine;

    @Override
    public void init() throws ServletException {

        // 1.获取ServletContext对象
        ServletContext servletContext = this.getServletContext();

        // 2.创建Thymeleaf解析器对象
        ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(servletContext);

        // 3.给解析器对象设置参数
        // ①HTML是默认模式,明确设置是为了代码更容易理解
        templateResolver.setTemplateMode(TemplateMode.HTML);

        // ②设置前缀
        String viewPrefix = servletContext.getInitParameter("view-prefix");

        templateResolver.setPrefix(viewPrefix);

        // ③设置后缀
        String viewSuffix = servletContext.getInitParameter("view-suffix");

        templateResolver.setSuffix(viewSuffix);

        // ④设置缓存过期时间(毫秒)
        templateResolver.setCacheTTLMs(60000L);

        // ⑤设置是否缓存
        templateResolver.setCacheable(true);

        // ⑥设置服务器端编码方式
        templateResolver.setCharacterEncoding("utf-8");

        // 4.创建模板引擎对象
        templateEngine = new TemplateEngine();

        // 5.给模板引擎对象设置模板解析器
        templateEngine.setTemplateResolver(templateResolver);

    }

    protected void processTemplate(String templateName, HttpServletRequest req, HttpServletResponse resp) throws IOException {
        // 1.设置响应体内容类型和字符集
        resp.setContentType("text/html;charset=UTF-8");

        // 2.创建WebContext对象
        WebContext webContext = new WebContext(req, resp, getServletContext());

        // 3.处理模板数据
        templateEngine.process(templateName, webContext, resp.getWriter());
    }
}

特别提醒:这个类不需要掌握,因为以后都被框架封装了,我们现在只是暂时用一下。

在这里插入图片描述

1.5、声明初始化参数

在这里插入图片描述

<!-- 配置 Web 应用初始化参数指定视图前缀、后缀 -->
<!-- 
    物理视图举例:/WEB-INF/pages/index.html
    对应逻辑视图:index
-->
<context-param>
    <param-name>view-prefix</param-name>
    <param-value>/WEB-INF/pages/</param-value>
</context-param>
<context-param>
    <param-name>view-suffix</param-name>
    <param-value>.html</param-value>
</context-param>

1.6、Thymeleaf 的页面语法

后续单独介绍

2、ModelBaseServlet

2.1、提出问题

2.1.1、我们的需求

在这里插入图片描述

2.1.2、HttpServlet 的局限
  • doGet() 方法:处理 GET 请求
  • doPost() 方法:处理 POST 请求

2.2、解决方案

  • 每个请求附带一个请求参数,表明自己要调用的目标方法
  • Servlet 根据目标方法名通过反射调用目标方法

2.3、ModelBaseServlet 完整代码

在这里插入图片描述

特别提醒:为了配合 TransactionFilter 实现事务控制,捕获的异常必须抛出。

public class ModelBaseServlet extends ViewBaseServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        // 在doGet()方法中调用doPost()方法,这样就可以在doPost()方法中集中处理所有请求
        doPost(request, response);
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        // 1.在所有request.getParameter()前面设置解析请求体的字符集
        request.setCharacterEncoding("UTF-8");

        // 2.从请求参数中获取method对应的数据
        String method = request.getParameter("method");

        // 3.通过反射调用method对应的方法
        // ①获取Class对象
        Class<? extends ModelBaseServlet> clazz = this.getClass();

        try {
            // ②获取method对应的Method对象
            Method methodObject = clazz.getDeclaredMethod(method, HttpServletRequest.class, HttpServletResponse.class);

            // ③打开访问权限
            methodObject.setAccessible(true);

            // ④通过Method对象调用目标方法
            methodObject.invoke(this, request, response);
        } catch (Exception e) {
            e.printStackTrace();

            // 重要提醒:为了配合 TransactionFilter 实现事务控制,捕获的异常必须抛出。
            throw new RuntimeException(e);
        }
    }

}

2.4、继承关系

在这里插入图片描述

第五节 搭建环境:辅助功能

1、常量类

在这里插入图片描述

public class ImperialCourtConst {

    public static final String LOGIN_FAILED_MESSAGE = "账号、密码错误,不可进宫!";
    public static final String ACCESS_DENIED_MESSAGE = "宫闱禁地,不得擅入!";

}

2、MD5 加密工具方法

在这里插入图片描述

public class MD5Util {

    /**
     * 针对明文字符串执行MD5加密
     * @param source
     * @return
     */
    public static String encode(String source) {

        // 1.判断明文字符串是否有效
        if (source == null || "".equals(source)) {
            throw new RuntimeException("用于加密的明文不可为空");
        }

        // 2.声明算法名称
        String algorithm = "md5";

        // 3.获取MessageDigest对象
        MessageDigest messageDigest = null;
        try {
            messageDigest = MessageDigest.getInstance(algorithm);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }

        // 4.获取明文字符串对应的字节数组
        byte[] input = source.getBytes();

        // 5.执行加密
        byte[] output = messageDigest.digest(input);

        // 6.创建BigInteger对象
        int signum = 1;
        BigInteger bigInteger = new BigInteger(signum, output);

        // 7.按照16进制将bigInteger的值转换为字符串
        int radix = 16;
        String encoded = bigInteger.toString(radix).toUpperCase();

        return encoded;
    }

}

3、日志配置文件

在这里插入图片描述

<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true">
    <!-- 指定日志输出的位置 -->
    <appender name="STDOUT"
              class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <!-- 日志输出的格式 -->
            <!-- 按照顺序分别是:时间、日志级别、线程名称、打印日志的类、日志主体内容、换行 -->
            <pattern>[%d{HH:mm:ss.SSS}] [%-5level] [%thread] [%logger] [%msg]%n</pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <!-- 设置全局日志级别。日志级别按顺序分别是:DEBUG、INFO、WARN、ERROR -->
    <!-- 指定任何一个日志级别都只打印当前级别和后面级别的日志。 -->
    <root level="INFO">
        <!-- 指定打印日志的appender,这里通过“STDOUT”引用了前面配置的appender -->
        <appender-ref ref="STDOUT" />
    </root>

    <!-- 专门给某一个包指定日志级别 -->
    <logger name="com.atguigu" level="DEBUG" additivity="false">
        <appender-ref ref="STDOUT" />
    </logger>

</configuration>

本文章参考B站 尚硅谷2022版Maven教程(maven入门+高深,全网无出其右!),仅供个人学习使用,部分内容为本人自己见解,与尚硅谷无关。

<think>好的,我现在需要帮助用户解决关于使用IntelliJ IDEA从零开始构建分布式架构项目的问题。用户之前已经得到了一些分步指南,现在根据提供的站内引用和之前的回答,我需要进一步优化回答,并确保符合用户的需求和引用内容。 首先,我需要回顾用户提供的引用内容。引用[1]到[5]主要涉及IDEA的项目创建、模块管理、构建工具使用以及多模块项目的配置。特别是引用[2]和[4]强调了IDEA中Project和Module的结构,与Eclipse的不同之处,比如一个Project对应一个窗口,多Module结构适合分布式项目。引用[5]提到了如何创建子模块并添加依赖,这在实际的多模块项目搭建中非常关键。 用户当前的问题是寻找零基础教程,因此需要从最基础的步骤开始,结合这些引用内容。用户可能对IDEA的界面和概念不太熟悉,所以需要详细解释每个步骤,特别是如何创建Project、添加Module、配置依赖等。同时,用户之前的问题中提到了使用Spring Cloud Alibaba组件,如Nacos、Seata等,需要将这些技术整合到教程中,确保步骤连贯。 接下来,我需要确保回答结构清晰,分步骤进行,并引用相关的内容来支持说明。例如,在创建多模块项目时,引用[2]和[4]的Project和Module结构说明非常重要,需要明确指出IDEA中的项目结构与Eclipse的不同,避免用户混淆。此外,引用[5]中的pom.xml配置示例可以用来展示如何添加模块依赖,确保各个子模块能够正确引用公共模块。 另外,用户可能遇到的常见问题,比如依赖冲突、配置错误等,需要提供解决方案,如使用Maven的依赖树分析,或者如何通过IDEA的构建工具窗口管理任务(引用[3])。同时,分布式架构中的服务注册、配置中心设置等步骤需要详细说明,可能结合代码示例和配置文件,确保用户能够跟随操作。 在验证部分,需要指导用户如何测试服务注册是否成功,网关路由是否生效,这可以通过curl命令或IDEA内置的HTTP客户端来实现。此外,分布式事务和链路追踪的集成可能需要额外的步骤,比如引入Seata和Sleuth,但根据用户之前的回答,这些内容可能已经涵盖,需要简要提及并引导用户参考之前的指南或相关文档。 最后,生成的相关问题需要围绕用户可能进一步关心的主题,如具体组件的配置细节、调试技巧、部署策略等,确保用户能够找到后续的学习路径。 总结来说,我需要将站内引用中的关键点融入教程步骤,确保每个环节都有据可依,同时保持语言简洁明了,适合零基础用户理解。需要特别注意IDEA特有的操作,如多窗口管理、模块创建、依赖配置等,避免用户在使用过程中因IDE差异而遇到障碍。</think>### 从零开始使用IntelliJ IDEA构建分布式架构项目实战指南 --- #### 一、项目创建与多模块搭建(结合引用[2][4][5]) 1. **创建父工程** - 选择菜单栏 `File → New → Project` - 选择`Maven` → 勾选`Create from archetype` → 选择`org.apache.maven.archetypes:maven-archetype-quickstart` - 填写GroupId(如`com.example`)和ArtifactId(如`distributed-parent`) - **关键配置**:父工程pom.xml需添加`<packaging>pom</packaging>` 2. **添加子模块** - 右键父工程 → `New → Module` - 选择`Maven` → 命名模块(如`service-order`) - 重复创建`common`, `gateway`, `service-auth`等模块 - **注意**:每个模块的pom.xml需继承父工程[^2] ```xml <!-- 子模块示例:service-product/pom.xml --> <parent> <groupId>com.example</groupId> <artifactId>distributed-parent</artifactId> <version>1.0-SNAPSHOT</version> </parent> ``` --- #### 、分布式组件集成(基于Spring Cloud Alibaba) 1. **服务注册与发现(Nacos)** - 在`common`模块添加依赖: ```xml <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> ``` - 子模块启动类添加注解`@EnableDiscoveryClient`[^1] 2. **跨模块依赖配置(引用[5])** ```xml <!-- service-order模块依赖common模块 --> <dependency> <groupId>com.example</groupId> <artifactId>common</artifactId> <version>${project.version}</version> </dependency> ``` --- #### 三、核心功能开发 1. **API网关配置(Spring Cloud Gateway)** ```yaml # gateway模块application.yml spring: cloud: gateway: routes: - id: auth_route uri: lb://service-auth predicates: - Path=/api/auth/** ``` 2. **服务间通信(OpenFeign)** ```java // 在service-order模块创建Feign客户端 @FeignClient(name = "service-product", path = "/products") public interface ProductFeignClient { @GetMapping("/{id}") ProductDTO getById(@PathVariable Long id); } ``` --- #### 四、项目验证与调试 1. **启动顺序建议**: ``` 1. Nacos Server(控制台http://localhost:8848) 2. 网关服务(gateway) 3. 业务服务(service-auth/service-order等) ``` 2. **服务发现验证**: ```bash # 查看注册服务列表 curl http://localhost:8848/nacos/v1/ns/service/list ``` 3. **接口调试技巧**: - 使用IDEA内置HTTP Client工具 - 示例请求: ``` GET http://localhost:8080/api/order/1 Authorization: Bearer token ``` --- #### 五、典型问题解决方案 1. **依赖冲突排查**: - 在IDEA右侧Maven面板 → 点击`Show Dependencies`生成依赖树 - 使用`mvn dependency:tree -Dverbose`命令分析[^3] 2. **多模块热部署**: - 开启`Build → Compile → Build Project automatically` - 添加`spring-boot-devtools`依赖 3. **配置中心使用**: ```yaml # 在nacos控制台创建dataId:service-auth-dev.yaml spring: cloud: nacos: config: server-addr: localhost:8848 file-extension: yaml ``` --- $$ \text{分布式系统设计原则} = \begin{cases} \text{单一职责} & \text{每个服务独立部署} \\ \text{最终一致性} & \text{允许短时数据不一致} \\ \text{容错设计} & \text{熔断+降级+限流} \end{cases} $$ ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值