Fit for tomcat deployment

This commit is contained in:
Patrick Haßel 2022-03-23 11:30:46 +01:00
parent 172ee3a337
commit 536218920a
20 changed files with 82 additions and 182 deletions

2
.gitignore vendored
View File

@ -2,4 +2,4 @@
/target/
/.idea/
/.jpb/
/application.properties
/*.db

10
application.properties Normal file
View File

@ -0,0 +1,10 @@
#logging.level.de.ph87.homeautomation=DEBUG
#-
spring.datasource.url=jdbc:h2:./Homeautomation;AUTO_SERVER=TRUE;DB_CLOSE_ON_EXIT=FALSE
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
#-
spring.jpa.hibernate.ddl-auto=update
de.ph87.homeautomation.insert-demo-data=true

View File

@ -1,7 +0,0 @@
#!/bin/bash
cd "$(dirname "$0")" || exit 1
mvn clean package spring-boot:repackage && \
scp target/Homeautomation.jar media@10.0.0.50:/home/media/java/Homeautomation/Homeautomation.jar.update && \
curl -m 2 -s http://10.0.0.50:8080/server/shutdown && echo "Server restarting..." || echo "Failed to restart server!"

34
pom.xml
View File

@ -7,16 +7,17 @@
<groupId>de.ph87</groupId>
<artifactId>Homeautomation</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<maven.compiler.source>15</maven.compiler.source>
<maven.compiler.target>15</maven.compiler.target>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.6.RELEASE</version>
<version>2.6.4</version>
</parent>
<dependencies>
@ -28,10 +29,6 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
@ -40,15 +37,24 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
</dependency>
<dependency>
@ -148,18 +154,6 @@
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<configuration>
<mainClass>de.ph87.homeautomation.BackendApplication</mainClass>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>

View File

@ -1,5 +1,8 @@
# See http://help.github.com/ignore-files/ for more about ignoring files.
/node/
### PATRICK
/node
### END
# compiled output
/dist

View File

@ -4,7 +4,7 @@
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"build": "ng build --base-href /Homeautomation/",
"watch": "ng build --watch --configuration development",
"test": "ng test"
},

View File

@ -5,6 +5,7 @@ import {environment} from "../../environments/environment";
import {Subject} from "rxjs";
import {CompatClient, Stomp} from "@stomp/stompjs";
import {Update} from "./Update";
import {LocationStrategy} from "@angular/common";
export function NO_OP() {
}
@ -21,7 +22,7 @@ function errorInterceptor(errorHandler: (error: any) => void): ((error: any) =>
}
@Injectable({
providedIn: 'root'
providedIn: 'root',
})
export class ApiService {
@ -30,10 +31,12 @@ export class ApiService {
private updateSubject = new Subject<Update<object>>();
constructor(
private http: HttpClient,
protected readonly http: HttpClient,
protected readonly locationStrategy: LocationStrategy,
) {
const url = this.websocketUrl("websocket");
this.webSocketClient = Stomp.over(function () {
return new WebSocket(ApiService.url("ws", "websocket"));
return new WebSocket(url);
});
this.webSocketClient.debug = () => null;
this.webSocketClient.connect({}, () => {
@ -46,27 +49,31 @@ export class ApiService {
}
getItem<T>(path: string, fromJson: (json: any) => T, next: (item: T) => void = NO_OP, error: (error: any) => void = NO_OP) {
this.http.get<any>(ApiService.url("http", path)).pipe(map(fromJson)).subscribe(next, errorInterceptor(error));
this.http.get<any>(this.restUrl(path)).pipe(map(fromJson)).subscribe(next, errorInterceptor(error));
}
getList<T>(path: string, fromJson: (json: any) => T, compare: (a: T, b: T) => number = NO_COMPARE, next: (list: T[]) => void = NO_OP, error: (error: any) => void = NO_OP) {
this.http.get<any[]>(ApiService.url("http", path)).pipe(map(list => list.map(fromJson).sort(compare))).subscribe(next, errorInterceptor(error));
this.http.get<any[]>(this.restUrl(path)).pipe(map(list => list.map(fromJson).sort(compare))).subscribe(next, errorInterceptor(error));
}
postReturnNone<T>(path: string, data: any, next: (_: void) => void = NO_OP, error: (error: any) => void = NO_OP) {
this.http.post<any>(ApiService.url("http", path), data).subscribe(next, errorInterceptor(error));
this.http.post<any>(this.restUrl(path), data).subscribe(next, errorInterceptor(error));
}
postReturnItem<T>(path: string, data: any, fromJson: (json: any) => T, next: (item: T) => void = NO_OP, error: (error: any) => void = NO_OP) {
this.http.post<any>(ApiService.url("http", path), data).pipe(map(fromJson)).subscribe(next, errorInterceptor(error));
this.http.post<any>(this.restUrl(path), data).pipe(map(fromJson)).subscribe(next, errorInterceptor(error));
}
postReturnList<T>(path: string, data: any, fromJson: (json: any) => T, next: (list: T[]) => void = NO_OP, error: (error: any) => void = NO_OP) {
this.http.post<any>(ApiService.url("http", path), data).pipe(map(list => list.map(fromJson))).subscribe(next, errorInterceptor(error));
this.http.post<any>(this.restUrl(path), data).pipe(map(list => list.map(fromJson))).subscribe(next, errorInterceptor(error));
}
private static url(schema: string, path: string): string {
return schema + "://" + environment.host + ":" + environment.port + "/" + path;
private restUrl(path: string): string {
return environment.restBase + this.locationStrategy.getBaseHref() + path;
}
private websocketUrl(path: string) {
return environment.websocketBase + this.locationStrategy.getBaseHref() + path;
}
}

View File

@ -3,8 +3,8 @@ import {ComponentFixture, TestBed} from '@angular/core/testing';
import {SearchComponent} from './search.component';
describe('SearchComponent', () => {
let component: SearchComponent;
let fixture: ComponentFixture<SearchComponent>;
let component: SearchComponent<any>;
let fixture: ComponentFixture<SearchComponent<any>>;
beforeEach(async () => {
await TestBed.configureTestingModule({

View File

@ -0,0 +1,6 @@
const secure: boolean = window.location.protocol === "https:";
const host: string = window.location.host.split(":", 1)[0];
export function getBaseUrl(protocol: string, port: number) {
return protocol + (secure ? 's' : '') + "://" + host + ":" + port;
}

View File

@ -1,5 +1,7 @@
import {getBaseUrl} from "./UrlHelper";
export const environment = {
production: true,
host: window.location.host.split(":")[0],
port: window.location.port,
restBase: '',
websocketBase: getBaseUrl('ws', parseInt(window.location.port)),
};

View File

@ -2,10 +2,12 @@
// `ng build` replaces `environment.ts` with `environment.prod.ts`.
// The list of file replacements can be found in `angular.json`.
import {getBaseUrl} from "./UrlHelper";
export const environment = {
production: false,
host: window.location.host.split(":")[0],
port: 8080,
restBase: getBaseUrl('http', 8080),
websocketBase: getBaseUrl('ws', 8080),
};
/*

View File

@ -8,6 +8,6 @@
<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
<app-root></app-root>
<app-root></app-root>
</body>
</html>

View File

@ -1,28 +1,14 @@
package de.ph87.homeautomation;
import de.ph87.homeautomation.knx.group.KnxGroupImportService;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import javax.annotation.PostConstruct;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
@SpringBootApplication
@RequiredArgsConstructor
public class BackendApplication {
private final DemoDataService demoDataService;
private final KnxGroupImportService knxGroupImportService;
public class BackendApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(BackendApplication.class);
}
@PostConstruct
public void postConstruct() {
knxGroupImportService.importGroups();
demoDataService.insertDemoData();
}
}

View File

@ -2,7 +2,6 @@ package de.ph87.homeautomation;
import com.luckycatlabs.sunrisesunset.Zenith;
import de.ph87.homeautomation.channel.Channel;
import de.ph87.homeautomation.device.DeviceRepository;
import de.ph87.homeautomation.device.DeviceWriteService;
import de.ph87.homeautomation.device.devices.DeviceDto;
import de.ph87.homeautomation.knx.group.KnxGroup;
@ -10,12 +9,10 @@ import de.ph87.homeautomation.knx.group.KnxGroupReadService;
import de.ph87.homeautomation.logic.Logic;
import de.ph87.homeautomation.logic.LogicOperator;
import de.ph87.homeautomation.logic.LogicRepository;
import de.ph87.homeautomation.logic.LogicWriter;
import de.ph87.homeautomation.property.Property;
import de.ph87.homeautomation.property.PropertyRepository;
import de.ph87.homeautomation.property.PropertyType;
import de.ph87.homeautomation.scene.SceneDto;
import de.ph87.homeautomation.scene.SceneRepository;
import de.ph87.homeautomation.scene.SceneWriteService;
import de.ph87.homeautomation.schedule.Schedule;
import de.ph87.homeautomation.schedule.ScheduleRepository;
@ -45,17 +42,13 @@ public class DemoDataService {
private final DeviceWriteService deviceWriteService;
private final DeviceRepository deviceRepository;
private final PropertyRepository propertyRepository;
private final KnxGroupReadService knxGroupReadService;
private final SceneRepository sceneRepository;
private final SceneWriteService sceneWriteService;
private final LogicWriter logicWriter;
private final LogicRepository logicRepository;
@ -172,7 +165,7 @@ public class DemoDataService {
}
private KnxGroup knx(final int main, final int mid, final int sub) {
return knxGroupReadService.getByAddress(main, mid, sub);
return knxGroupReadService.getByAddress(main, mid, sub).orElse(null);
}
private Property createProperty(final String title, final PropertyType type, final Channel readChannel, final Channel writeChannel) {

View File

@ -1,20 +0,0 @@
package de.ph87.homeautomation;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("server")
@RequiredArgsConstructor
public class ServerController {
private final ServerService serverService;
@GetMapping("shutdown")
public void shutdown() {
serverService.shutdown();
}
}

View File

@ -1,43 +0,0 @@
package de.ph87.homeautomation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Service;
@Slf4j
@Service
@EnableAsync
@RequiredArgsConstructor
public class ServerService implements ApplicationContextAware {
private static final int DELAY_SECONDS = 1;
private ConfigurableApplicationContext applicationContext;
@Async
public void shutdown() {
try {
for (int delay = DELAY_SECONDS; delay > 0; delay--) {
log.info("Shutdown in {} second.", delay);
Thread.sleep(1000);
}
} catch (InterruptedException e) {
log.warn("Shutdown interrupted.");
return;
}
applicationContext.close();
System.exit(0);
}
@Override
public void setApplicationContext(ApplicationContext ctx) throws BeansException {
this.applicationContext = (ConfigurableApplicationContext) ctx;
}
}

View File

@ -1,5 +1,7 @@
package de.ph87.homeautomation.property;
package de.ph87.homeautomation;
import de.ph87.homeautomation.knx.group.KnxGroupImportService;
import de.ph87.homeautomation.property.PropertyWriteService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.event.ApplicationStartedEvent;
@ -9,12 +11,18 @@ import org.springframework.stereotype.Service;
@Slf4j
@Service
@RequiredArgsConstructor
public class PropertyEventListener {
public class StartupService {
private final KnxGroupImportService knxGroupImportService;
private final DemoDataService demoDataService;
private final PropertyWriteService propertyWriteService;
@EventListener(ApplicationStartedEvent.class)
public void onApplicationStarted() {
public void startup() {
knxGroupImportService.importGroups();
demoDataService.insertDemoData();
propertyWriteService.updateAllProperties();
}

View File

@ -7,6 +7,7 @@ import org.springframework.transaction.annotation.Transactional;
import tuwien.auto.calimero.GroupAddress;
import java.util.List;
import java.util.Optional;
@Slf4j
@Service
@ -16,8 +17,8 @@ public class KnxGroupReadService {
private final KnxGroupRepository knxGroupRepository;
public KnxGroup getByAddress(final int main, final int mid, final int sub) {
return knxGroupRepository.findByAddressRaw(new GroupAddress(main, mid, sub).getRawAddress()).orElseThrow(RuntimeException::new);
public Optional<KnxGroup> getByAddress(final int main, final int mid, final int sub) {
return knxGroupRepository.findByAddressRaw(new GroupAddress(main, mid, sub).getRawAddress());
}
public List<KnxGroup> findAll() {

View File

@ -1,18 +1,9 @@
package de.ph87.homeautomation.web;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.firewall.HttpFirewall;
import org.springframework.security.web.firewall.StrictHttpFirewall;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@ -21,34 +12,8 @@ import org.springframework.web.servlet.resource.PathResourceResolver;
import java.io.IOException;
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class WebConfig extends WebSecurityConfigurerAdapter implements WebMvcConfigurer {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors();
http.csrf().disable();
http.authorizeRequests().anyRequest().permitAll();
}
@Override
public void configure(WebSecurity web) {
web.httpFirewall(allowUrlEncodedSlashHttpFirewall());
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public HttpFirewall allowUrlEncodedSlashHttpFirewall() {
final StrictHttpFirewall firewall = new StrictHttpFirewall();
firewall.setAllowUrlEncodedSlash(true);
firewall.setAllowSemicolon(true);
return firewall;
}
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {

View File

@ -1,17 +1,10 @@
logging.level.root=WARN
logging.level.de.ph87=INFO
#-
spring.datasource.url=jdbc:h2:./Homeautomation;AUTO_SERVER=TRUE;DB_CLOSE_ON_EXIT=FALSE
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
#-
spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyComponentPathImpl
spring.jpa.hibernate.ddl-auto=update
spring.jpa.open-in-view=false
#-
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
#-
spring.jackson.serialization.indent_output=true
#-
spring.main.banner-mode=off