# SpringBoot-Admin **Repository Path**: ZhangTurtle/spring-boot-admin ## Basic Information - **Project Name**: SpringBoot-Admin - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-03-12 - **Last Updated**: 2024-03-13 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README > 声明:项目案例托管至Gitee:[https://gitee.com/ZhangTurtle/spring-boot-admin.git](https://gitee.com/ZhangTurtle/spring-boot-admin.git) 【**前情提要**】Spring Boot Actuator 提供了对单个 Spring Boot 应用的监控,信息包含应用状态、内存、线程、堆栈等,比较全面的监控了 Spring Boot 应用的整个生命周期。 但是这样监控也有一些问题: 第一,所有的监控都需要调用固定的接口来查看,如果全面查看应用状态需要调用很多接口,并且接口返回的 JSON 信息不方便运营人员理解; 第二,如果 Spring Boot 应用集群非常大,每个应用都需要调用不同的接口来查看监控信息,操作非常繁琐低效。在这样的背景下,就诞生了另外一个开源软件:**Spring Boot Admin**。 :::success 基于SpringBootAdmin的开源产品很多,我们选择:[https://github.com/codecentric/spring-boot-admin](https://github.com/codecentric/spring-boot-admin) ::: [spring-boot-admin与spring-boot和spring-cloud版本关系_springboot 项目不使用springcloud能用springboot admin么-CSDN博客](https://blog.csdn.net/q283614346/article/details/121146721) ### 0.demo 搭建使用聚合项目搭建 项目结构: ![image.png](https://cdn.nlark.com/yuque/0/2024/png/34561134/1710227425552-928e8f5f-910a-4bc1-840a-f39bae4a6848.png#averageHue=%23393f43&clientId=u7ca73b7a-4cda-4&from=paste&height=185&id=u0c12f152&originHeight=185&originWidth=546&originalType=binary&ratio=1&rotation=0&showTitle=false&size=13764&status=done&style=none&taskId=u7173af27-83b6-4156-b911-0d97930859e&title=&width=546) 父项目的 pom 依赖如下: ```xml 4.0.0 com.turtle springboot-admin pom 1.0-SNAPSHOT springboot-admin-server springboot-admin-client-a springboot-admin-client-b org.springframework.boot spring-boot-starter-parent 2.5.4 org.springframework.cloud spring-cloud-dependencies 2020.0.1 pom import org.springframework.boot spring-boot-maven-plugin ``` ### 1.搭建Admin服务器(新建 Server 端) 创建建对应的SpringBoot项目,添加相关依赖 ```xml springboot-admin com.turtle 1.0-SNAPSHOT 4.0.0 springboot-admin-server de.codecentric spring-boot-admin-server 2.5.1 de.codecentric spring-boot-admin-server-ui 2.5.1 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-maven-plugin ``` 启动类添加对应注解(@EnableAdminServer),放开Admin服务 ```java package com.turtle.server; import de.codecentric.boot.admin.server.config.EnableAdminServer; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @EnableAdminServer @SpringBootApplication public class BootAdminApplication { public static void main(String[] args) { SpringApplication.run(BootAdminApplication.class, args); } } ``` 启动springboot-admin-server服务,访问地址:[http://127.0.0.1:8762/](http://127.0.0.1:8762/) 这个时候没有服务注册,所以是空的,创建对应的客户端来被监控即可 ![](https://cdn.nlark.com/yuque/0/2024/png/34561134/1710215876390-81e0de13-1495-4b1f-b9f9-503a685269ba.png#averageHue=%23484848&height=897&id=YajUf&originHeight=897&originWidth=1892&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=&width=1892) ### 2.客户端配置 创建一个SpringBoot项目整合Actuator后添加Admin的客户端依赖 ```xml springboot-admin com.turtle 1.0-SNAPSHOT 4.0.0 springboot-admin-client-a de.codecentric spring-boot-admin-starter-client 2.1.6 org.springframework.boot spring-boot-starter-web ``` 然后在属性文件中添加服务端的配置和Actuator的基本配置 ```yaml spring: boot: admin: client: url: http://localhost:8762 #server端地址 instance: service-base-url: http://localhost:8766 #client地址, #不配置的情况下,在打包的时候会有提示。不影响运行。 application: name: client-a management: endpoints: web: exposure: include: "*" endpoint: health: show-details: ALWAYS info: version: @project.version@ groupId: @project.groupId@ artifactId: @project.artifactId@ server: port: 8766 ``` 刷新Admin的服务端页面,可看到服务被监控![image.png](https://cdn.nlark.com/yuque/0/2024/png/34561134/1710227889939-8e34ac30-201a-446f-a954-47ec652941db.png#averageHue=%23aa9875&clientId=u7ca73b7a-4cda-4&from=paste&height=899&id=ucfc1c99e&originHeight=899&originWidth=1426&originalType=binary&ratio=1&rotation=0&showTitle=false&size=76689&status=done&style=none&taskId=u1139109f-2130-4254-8215-5b1301094f0&title=&width=1426) 我们就可以在这个可视化的界面来处理操作了![image.png](https://cdn.nlark.com/yuque/0/2024/png/34561134/1710227910101-fab1f5aa-d0ca-497d-adf6-56c5d64d0745.png#averageHue=%23efefee&clientId=u7ca73b7a-4cda-4&from=paste&height=874&id=ud316e921&originHeight=874&originWidth=1841&originalType=binary&ratio=1&rotation=0&showTitle=false&size=100218&status=done&style=none&taskId=u8b0dc304-7378-4021-aa1d-d04ea5db11b&title=&width=1841) :::success PS: 按照同样的步骤创建客户端B,将服务暴露,被admin监控 ::: ![image.png](https://cdn.nlark.com/yuque/0/2024/png/34561134/1710227978928-78e001ea-caef-49dc-95e4-07a72b2a748d.png#averageHue=%23b1ac92&clientId=u7ca73b7a-4cda-4&from=paste&height=898&id=u62ec38ae&originHeight=898&originWidth=1641&originalType=binary&ratio=1&rotation=0&showTitle=false&size=112274&status=done&style=none&taskId=u3f4c719b-b4eb-421d-8ad3-86f1fe6da35&title=&width=1641) ### 3.服务状态 我们可以监控下MySQL的状态,在springboot-admin-client-a模块中添加对应的数据库依赖 ```xml org.springframework.boot spring-boot-starter-web mysql mysql-connector-java ``` ```xml springboot-admin com.turtle 1.0-SNAPSHOT 4.0.0 springboot-admin-client-a de.codecentric spring-boot-admin-starter-client 2.1.6 org.springframework.boot spring-boot-starter-web mysql mysql-connector-java org.springframework.boot spring-boot-starter-jdbc ``` 然后添加对应的jdbc配置(spring.datasource.xxx) ```yaml spring: boot: admin: client: url: http://localhost:8762 #server端地址 instance: service-base-url: http://localhost:8766 #client地址, #不配置的情况下,在打包的时候会有提示。不影响运行。 application: name: client-a datasource: driverClassName: com.mysql.cj.jdbc.Driver url: jdbc:mysql://120.55.48.103:3306/mysql?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true username: root password: root management: endpoints: web: exposure: include: "*" endpoint: health: show-details: ALWAYS info: version: @project.version@ groupId: @project.groupId@ artifactId: @project.artifactId@ server: port: 8766 ``` 然后我们在Admin中的health中就可以看到对应的数据库连接信息![image.png](https://cdn.nlark.com/yuque/0/2024/png/34561134/1710228590615-4e3d4af3-c099-49d8-97b1-45e3f8b905c5.png#averageHue=%23eeeeee&clientId=u7ca73b7a-4cda-4&from=paste&height=839&id=u5398d084&originHeight=839&originWidth=1835&originalType=binary&ratio=1&rotation=0&showTitle=false&size=91273&status=done&style=none&taskId=uc0ff5585-203f-42fe-95c9-c098f775f7d&title=&width=1835) 测试: 当我把MySQL数据库关闭后,查看springboot admin的监控面板信息: ![image.png](https://cdn.nlark.com/yuque/0/2024/png/34561134/1710228774582-d4fd627b-f027-4a01-8fb1-8f10049daf39.png#averageHue=%23090605&clientId=u7ca73b7a-4cda-4&from=paste&height=127&id=udc23c0fd&originHeight=127&originWidth=1010&originalType=binary&ratio=1&rotation=0&showTitle=false&size=16226&status=done&style=none&taskId=u06d3bb02-ffe1-4616-bcc5-d59ac2c0fc3&title=&width=1010) 可以看到Admin中的应用墙变灰了 ![image.png](https://cdn.nlark.com/yuque/0/2024/png/34561134/1710228798085-76397c49-e5c2-4084-9383-6bc9647109c1.png#averageHue=%23616161&clientId=u7ca73b7a-4cda-4&from=paste&height=906&id=uaef295ad&originHeight=906&originWidth=1700&originalType=binary&ratio=1&rotation=0&showTitle=false&size=116031&status=done&style=none&taskId=ub635e67d-0e8f-430b-91d1-b5ebcafc5a8&title=&width=1700) ![image.png](https://cdn.nlark.com/yuque/0/2024/png/34561134/1710228838246-369c9a61-7ee4-429c-acbe-5f21cb61c8c2.png#averageHue=%23ececec&clientId=u7ca73b7a-4cda-4&from=paste&height=823&id=u33858ab2&originHeight=823&originWidth=1838&originalType=binary&ratio=1&rotation=0&showTitle=false&size=101129&status=done&style=none&taskId=u9c7c6861-f1c3-4cba-a482-300095fc5d7&title=&width=1838) 重新启动mysql服务后,恢复正常,然后我们修改下数据库连接的超时时间 ```java # 数据库连接超时时间 spring.datasource.hikari.connection-timeout=2000 ``` 关闭数据库后,我们发现应用变红了 ![](https://cdn.nlark.com/yuque/0/2024/png/34561134/1710215877156-78f814c2-137f-437c-aa96-8e90767b4719.png#averageHue=%23c0c2ae&id=kSF3G&originHeight=858&originWidth=1512&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=) ![](https://cdn.nlark.com/yuque/0/2024/png/34561134/1710215877253-6c1f543f-959a-4bba-83e2-e6aa2df9b92e.png#averageHue=%23fdfcfc&id=WI7Jf&originHeight=717&originWidth=1658&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=) > 设置数据库连接超时后即可在有效的时间内发下应用的状态。 > - 绿色:正常状态 > - 灰色:连接客户端健康信息超时 > - 红色:可以看到具体的异常信息 ### 4.安全防护 其实我们可以发现在SpringBootAdmin的管理页面中我们是可以做很多的操作的,这时如果别人知道了对应的访问地址,想想是不是就觉得恐怖,所以必要的安全防护还是很有必要的,我们来看看具体应该怎么来处理 由于在分布式 web 应用程序中有几种解决身份验证和授权的方法,Spring Boot Admin 没有提供默认的方法。默认情况下,spring-boot-admin-server-ui 提供了一个登录页面和一个注销按钮,引入SpringSecurity进行权限管理。 在springboot-admin-server模块中导入依赖: ```xml org.springframework.boot spring-boot-starter-security ``` 然后在springboot-admin-server模块添加对应的配置类 ```java package com.turtle.server.configure; import de.codecentric.boot.admin.server.config.AdminServerProperties; import org.springframework.boot.autoconfigure.security.SecurityProperties; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; import org.springframework.security.web.csrf.CookieCsrfTokenRepository; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import java.util.UUID; // 使用lite模式 @Configuration(proxyBeanMethods = false) public class SecuritySecureConfig extends WebSecurityConfigurerAdapter { private final AdminServerProperties adminServer; private final SecurityProperties security; public SecuritySecureConfig(AdminServerProperties adminServer, SecurityProperties security) { this.adminServer = adminServer; this.security = security; } @Override protected void configure(HttpSecurity http) throws Exception { SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler(); successHandler.setTargetUrlParameter("redirectTo"); successHandler.setDefaultTargetUrl(this.adminServer.path("/")); http.authorizeRequests( (authorizeRequests) -> authorizeRequests.antMatchers(this.adminServer.path("/assets/**")).permitAll() .antMatchers(this.adminServer.path("/actuator/info")).permitAll() .antMatchers(this.adminServer.path("/actuator/health")).permitAll() .antMatchers(this.adminServer.path("/login")).permitAll().anyRequest().authenticated() ).formLogin( (formLogin) -> formLogin.loginPage(this.adminServer.path("/login")).successHandler(successHandler).and() ).logout((logout) -> logout.logoutUrl(this.adminServer.path("/logout"))).httpBasic(Customizer.withDefaults()) .csrf((csrf) -> csrf.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) .ignoringRequestMatchers( new AntPathRequestMatcher(this.adminServer.path("/instances"), HttpMethod.POST.toString()), new AntPathRequestMatcher(this.adminServer.path("/instances/*"), HttpMethod.DELETE.toString()), new AntPathRequestMatcher(this.adminServer.path("/actuator/**")) )) .rememberMe((rememberMe) -> rememberMe.key(UUID.randomUUID().toString()).tokenValiditySeconds(1209600)); } // Required to provide UserDetailsService for "remember functionality" // 需要为“记忆功能”提供UserDetailsService @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication().withUser(security.getUser().getName()) .password("{noop}" + security.getUser().getPassword()).roles("USER"); } } ``` 在springboot-admin-server模块配置文件中设置登录的账号密码 ```yaml server: port: 8762 spring: application: name: SpringBootAdmin security: user: name: admin password: admin #配置登录界面的UI显示标题 boot: admin: ui: title: ${spring.application.name} ``` 然后访问Admin管理页面,输入账号密码后可以进入,但是没有监控的应用了![image.png](https://cdn.nlark.com/yuque/0/2024/png/34561134/1710229350785-94445012-846d-4199-85d2-478f31014d53.png#averageHue=%23e9e9e9&clientId=u7ca73b7a-4cda-4&from=paste&height=525&id=u9f8dbc54&originHeight=525&originWidth=1563&originalType=binary&ratio=1&rotation=0&showTitle=false&size=33045&status=done&style=none&taskId=ue93d52d0-a628-44c6-9b4e-b5249e5fe38&title=&width=1563) 原因是被监控的服务要连接到Admin服务端也是需要认证的 ![image.png](https://cdn.nlark.com/yuque/0/2024/png/34561134/1710229242444-70e60ecf-d5aa-45f5-9ae0-f8d24a2d3d1e.png#averageHue=%23302f2e&clientId=u7ca73b7a-4cda-4&from=paste&height=363&id=u481b5202&originHeight=363&originWidth=1741&originalType=binary&ratio=1&rotation=0&showTitle=false&size=105555&status=done&style=none&taskId=uead11898-dd7c-4b4f-ad06-f04639c8af8&title=&width=1741) 我们在每个需要连接的客户端配置上连接的账号密码即可 ![image.png](https://cdn.nlark.com/yuque/0/2024/png/34561134/1710229412196-a5d0d26b-aff5-4daa-b9cb-cdc9e3e6d996.png#averageHue=%232c2b2b&clientId=u7ca73b7a-4cda-4&from=paste&height=425&id=uc1b83196&originHeight=425&originWidth=1111&originalType=binary&ratio=1&rotation=0&showTitle=false&size=50310&status=done&style=none&taskId=ubb0a0cbb-243b-4cbc-b8e8-2473bbd2532&title=&width=1111) ```yaml spring: boot: admin: client: url: http://localhost:8762 #server端地址 username: admin #对应server端的账号密码,不配置就监控不到这个client。 password: admin instance: service-base-url: http://localhost:8766 #client地址, #不配置的情况下,在打包的时候会有提示。不影响运行。 application: name: client-a datasource: driverClassName: com.mysql.cj.jdbc.Driver url: jdbc:mysql://120.55.48.103:3306/mysql?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true username: root password: root management: endpoints: web: exposure: include: "*" endpoint: health: show-details: ALWAYS info: version: @project.version@ groupId: @project.groupId@ artifactId: @project.artifactId@ server: port: 8766 ``` 重启后访问Admin服务管理页面,发现服务被注册上,对客户端B进行同样的操作即可![image.png](https://cdn.nlark.com/yuque/0/2024/png/34561134/1710229461293-dd7d2e12-689d-44b3-9901-bffe8827ff57.png#averageHue=%23e3e3e3&clientId=u7ca73b7a-4cda-4&from=paste&height=437&id=u3f593325&originHeight=437&originWidth=1513&originalType=binary&ratio=1&rotation=0&showTitle=false&size=38254&status=done&style=none&taskId=uae007d77-36ea-4879-b75c-0daa1a7a254&title=&width=1513) ### 5.注册中心 实际开发的时候我们可以需要涉及到的应用非常多,我们也都会把服务注册到注册中心中,比如nacos,Eureka等,接下来我们看看如何通过注册中心来集成客户端。就不需要每个客户端来集成了。 ![](https://cdn.nlark.com/yuque/0/2024/png/34561134/1710215878040-54f7fa2e-bbae-4f85-8f4e-8e7f765de2bb.png#averageHue=%23f8efe2&id=geqvA&originHeight=271&originWidth=570&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=) 变为下面的场景 ![](https://cdn.nlark.com/yuque/0/2024/png/34561134/1710215878148-fa9692f2-0f90-4415-84f5-1361af35f53e.png#averageHue=%23f9f1e8&id=VgYPn&originHeight=262&originWidth=808&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=) 那么我们需要先启动一个注册中心服务,我们以Nacos为例![image.png](https://cdn.nlark.com/yuque/0/2024/png/34561134/1710231004000-0d335817-bfe9-4b36-a07b-3850671f144e.png#averageHue=%23090605&clientId=u7ca73b7a-4cda-4&from=paste&height=356&id=u06e296cc&originHeight=356&originWidth=1357&originalType=binary&ratio=1&rotation=0&showTitle=false&size=57407&status=done&style=none&taskId=u3e04f271-b155-4a40-b0d4-2104de7cc11&title=&width=1357) 新建springboot-admin-client-nacos-a服务,添加Nacos的注册中心配置、Actuator的配置,所有要被监控的微服务都需要引入该依赖 ```xml springboot-admin com.turtle 1.0-SNAPSHOT 4.0.0 springboot-admin-client-nacos-a org.springframework.boot spring-boot-starter-actuator org.springframework.boot spring-boot-starter-web mysql mysql-connector-java org.springframework.boot spring-boot-starter-jdbc com.alibaba.cloud spring-cloud-starter-alibaba-nacos-discovery com.alibaba.cloud spring-cloud-alibaba-dependencies 2021.1 pom import ``` 配置Nacos服务,然后启动服务(该服务注册到Nacos中): ```yaml spring: application: name: client-nacos-a datasource: driverClassName: com.mysql.cj.jdbc.Driver url: jdbc:mysql://120.55.48.103:3306/mysql?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true username: root password: root cloud: nacos: discovery: server-addr: 120.55.48.103:8848 management: endpoints: web: exposure: include: "*" endpoint: health: show-details: ALWAYS info: version: @project.version@ groupId: @project.groupId@ artifactId: @project.artifactId@ server: port: 8786 ``` 新增springboot-admin-server-nacos服务(区别于之前的模块)配置nacos信息,将模块注册到Nacos中 ```xml springboot-admin com.turtle 1.0-SNAPSHOT 4.0.0 springboot-admin-server-nacos de.codecentric spring-boot-admin-starter-server 2.5.1 de.codecentric spring-boot-admin-server-ui 2.5.1 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-security com.alibaba.cloud spring-cloud-starter-alibaba-nacos-discovery org.springframework.boot spring-boot-starter-actuator com.alibaba.cloud spring-cloud-alibaba-dependencies 2021.1 pom import org.springframework.boot spring-boot-maven-plugin ``` ```yaml server: port: 8782 spring: application: name: SpringBootAdminNacos security: user: name: admin password: admin #配置登录界面的UI显示标题 boot: admin: ui: title: ${spring.application.name} cloud: nacos: discovery: server-addr: 120.55.48.103:8848 service: ${spring.application.name} #将自己也注册到监控中 management: endpoints: web: exposure: include: "*" endpoint: health: show-details: ALWAYS ``` 启动服务,我们就可以看到对应的服务了,按照同样的步骤新增b客户端,最终显示界面如下图(使用注册中心服务发现会有30s左右的延时,无直接使用client引入发现快): ![image.png](https://cdn.nlark.com/yuque/0/2024/png/34561134/1710299036835-14d8671d-fcd8-4c44-8f7a-7fca71b3d53d.png#averageHue=%23e7e6e6&clientId=u453fe449-af53-4&from=paste&height=486&id=ue7042167&originHeight=486&originWidth=1436&originalType=binary&ratio=1&rotation=0&showTitle=false&size=43466&status=done&style=none&taskId=u6a27156a-02dd-465e-b16b-5487975c9c2&title=&width=1436) ### 6.邮件通知 如果监控的服务出现了问题,下线了,我们希望通过邮箱通知的方式来告诉维护人员,在springboot-admin-server/nacos中添加mail依赖 ```xml org.springframework.boot spring-boot-starter-mail ``` 在个人邮箱配置COP3协议,拿到授权码 ![image.png](https://cdn.nlark.com/yuque/0/2024/png/34561134/1710235697706-6ac9db81-268a-4ed9-b64d-cf624d2e91dd.png#averageHue=%23e6e7ed&clientId=u7ca73b7a-4cda-4&from=paste&height=574&id=tgKAv&originHeight=574&originWidth=1065&originalType=binary&ratio=1&rotation=0&showTitle=false&size=63350&status=done&style=none&taskId=u2e3e944c-b848-4723-a06c-e6d85ef5965&title=&width=1065) 然后配置对应的邮箱信息 ```yaml server: port: 8782 spring: application: name: SpringBootAdminNacos security: user: name: admin password: admin #配置登录界面的UI显示标题 boot: admin: ui: title: ${spring.application.name} notify: mail: #收件人 to: xxxxxxxxxx@163.com #发件人 from: xxxxxxxxxx@qq.com cloud: nacos: discovery: server-addr: 120.55.48.103:8848 service: ${spring.application.name} mail: # 使用的邮箱服务 qq 163等 host: smtp.qq.com # 发送者 username: xxxxxxxxxx@qq.com # 授权码 password: xxxxxxxxxx #将自己也注册到监控中 management: endpoints: web: exposure: include: "*" endpoint: health: show-details: ALWAYS ``` 然后将客户端a、springboot-admin-server/nacos启动,待信息均被监控之后,将客户端a宕机,可以立即收到邮箱提醒 ![image.png](https://cdn.nlark.com/yuque/0/2024/png/34561134/1710235879004-679a1477-516e-46f6-b6ac-fdf1003f6859.png#averageHue=%23fbfaf7&clientId=u7ca73b7a-4cda-4&from=paste&height=659&id=PaqEU&originHeight=659&originWidth=1442&originalType=binary&ratio=1&rotation=0&showTitle=false&size=212811&status=done&style=none&taskId=u30c1f9cf-5795-43df-86d5-186c9853a48&title=&width=1442)